node.js npm npm-install package-lock.json

node.js - ¿Por qué "npm install" reescribe package-lock.json?



npm-install (10)

Recientemente actualicé a npm @ 5. Ahora tengo un archivo package-lock.json con todo, desde package.json. Esperaría que, cuando ejecuto npm install las versiones de dependencia se npm install del archivo de bloqueo para determinar qué se debe instalar en mi directorio node_modules. Lo extraño es que en realidad termina modificando y reescribiendo mi archivo package-lock.json.

Por ejemplo, el archivo de bloqueo tenía un mecanografiado especificado en la versión 2.1.6. Luego, después del npm install , la versión se cambió a 2.4.1. Eso parece derrotar todo el propósito de un archivo de bloqueo.

¿Qué me estoy perdiendo? ¿Cómo consigo que npm realmente respete mi archivo de bloqueo?


Descubrí que habrá una nueva versión de npm 5.7.1 con el nuevo comando npm ci , que se instalará solo desde package-lock.json

El nuevo comando npm ci se instala desde su archivo de bloqueo SOLAMENTE. Si su package.json y su archivo de bloqueo no están sincronizados, informará un error.

Funciona desechando sus node_modules y recreándolos desde cero.

Más allá de garantizarle que solo obtendrá lo que está en su archivo de bloqueo, también es mucho más rápido (2x-10x!) Que la instalación de npm cuando no comienza con un node_modules.

Como se puede deducir del nombre, esperamos que sea de gran ayuda para los entornos de integración continua. También esperamos que las personas que realizan implementaciones de producción a partir de etiquetas git vean grandes ganancias.


EDITAR: el nombre "bloqueo" es complicado, su NPM intenta ponerse al día con Yarn. No es un archivo bloqueado en absoluto. package.json es un archivo fijo por el usuario, que una vez "instalado" generará el árbol de carpetas node_modules y ese árbol se escribirá en package-lock.json . Como puede ver, es al revés: las versiones de dependencia se package-lock.json de package.json como siempre, y package-lock.json debería llamarse package-tree.json

(Espero que esto haya aclarado mi respuesta, después de tantos votos negativos)

Una respuesta simplista: package.json tiene sus dependencias como de costumbre, mientras que package-lock.json es "un árbol node_modules exacto y más importante reproducible" (tomado de npm docs ).

En cuanto al nombre complicado, su NPM intenta ponerse al día con Yarn.


En el futuro, podrá usar un indicador package-lock.json --from-lock-file (o similar) para instalar solo desde package-lock.json sin modificarlo.

Esto será útil para entornos de CI, etc., donde las construcciones reproducibles son importantes.

Consulte https://github.com/npm/npm/issues/18286 para el seguimiento de la función.



Parece que este problema se solucionó en npm v5.4.2

https://github.com/npm/npm/issues/17979

(Desplácese hasta el último comentario en el hilo)

Actualizar

Realmente arreglado en 5.6.0. Hubo un error multiplataforma en 5.4.2 que todavía causaba el problema.

https://github.com/npm/npm/issues/18712

Actualización 2

Vea mi respuesta aquí: https://.com/a/53680257/1611058

npm ci es el comando que debe usar al instalar proyectos existentes ahora.


Probablemente tengas algo como:

"typescript":"~2.1.6"

en su package.json que npm se actualiza a la última versión menor, en su caso es 2.4.1

Editar: Pregunta de OP

Pero eso no explica por qué "npm install" cambiaría el archivo de bloqueo. ¿No se pretende que el archivo de bloqueo cree una compilación reproducible? Si es así, independientemente del valor de semver, aún debe usar la misma versión 2.1.6.

Responder:

Esto está destinado a bloquear su árbol de dependencia completa. Digamos que typescript v2.4.1 requiere widget ~v1.0.0 . Cuando npm lo instala, toma el widget v1.0.0 . Más tarde, su compañero desarrollador (o compilación de CI) realiza una instalación npm y obtiene el typescript v2.4.1 pero el widget se ha actualizado al widget v1.0.1 . Ahora su módulo de nodo no está sincronizado. Esto es lo package-lock.json previene package-lock.json .

O más generalmente:

Como ejemplo, considere

paquete A:

{"nombre": "A", "versión": "0.1.0", "dependencias": {"B": "<0.1.0"}}

paquete B:

{"nombre": "B", "versión": "0.0.1", "dependencias": {"C": "<0.1.0"}}

y paquete C:

{"nombre": "C", "versión": "0.0.1"}

Si estas son las únicas versiones de A, B y C disponibles en el registro, se instalará una instalación normal de npm A:

[email protected] - [email protected] - [email protected]

Sin embargo, si se publica [email protected], se instalará una nueva instalación npm A:

[email protected] - [email protected] - [email protected] suponiendo que la nueva versión no modificó las dependencias de B. Por supuesto, la nueva versión de B podría incluir una nueva versión de C y cualquier cantidad de nuevas dependencias. Si dichos cambios no son deseables, el autor de A podría especificar una dependencia en [email protected]. Sin embargo, si el autor de A y el autor de B no son la misma persona, no hay forma de que el autor de A diga que él o ella no quiere obtener versiones recientemente publicadas de C cuando B no ha cambiado en absoluto.

OP Pregunta 2: Entonces déjame ver si entiendo correctamente. Lo que está diciendo es que el archivo de bloqueo especifica las versiones de las dependencias secundarias, pero aún se basa en la coincidencia aproximada de package.json para determinar las dependencias de nivel superior. ¿Es eso exacto?

Respuesta: No. package-lock bloquea todo el árbol de paquetes, incluidos los paquetes raíz descritos en package.json . Si typescript está bloqueado en 2.4.1 en su package-lock.json , debería permanecer así hasta que se cambie. Y digamos que mañana typescript lanza la versión 2.4.2 . Si npm install su sucursal y ejecuto npm install , npm respetará el archivo de bloqueo e instalará 2.4.1 .

Más sobre package-lock.json :

package-lock.json se genera automáticamente para cualquier operación en la que npm modifique el árbol node_modules o package.json. Describe el árbol exacto que se generó, de modo que las instalaciones posteriores pueden generar árboles idénticos, independientemente de las actualizaciones de dependencia intermedias.

Este archivo está destinado a ser confirmado en repositorios de origen y sirve para varios propósitos:

Describa una representación única de un árbol de dependencias de modo que se garantice que los compañeros de equipo, las implementaciones y la integración continua instalen exactamente las mismas dependencias.

Proporcione una facilidad para que los usuarios "viajen en el tiempo" a estados anteriores de node_modules sin tener que confirmar el directorio en sí.

Para facilitar una mayor visibilidad de los cambios de árbol a través de diferencias de control de fuente legible.

Y optimice el proceso de instalación permitiendo que npm omita las resoluciones de metadatos repetidos para paquetes instalados previamente.

https://docs.npmjs.com/files/package-lock.json


Use el comando npm ci lugar de npm install .

"ci" significa "integración continua".

Instalará las dependencias del proyecto basadas en el archivo package-lock.json en lugar de las dependencias indulgentes del archivo package.json.

Producirá construcciones idénticas para tus compañeros de equipo y también es mucho más rápido.

Puede leer más al respecto en esta publicación de blog: https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable


Use el recién introducido

npm ci

npm ci promete el mayor beneficio para los equipos grandes. Brindar a los desarrolladores la capacidad de "cerrar sesión" en un bloqueo de paquete promueve una colaboración más eficiente en equipos grandes, y la capacidad de instalar exactamente lo que está en un archivo de bloqueo tiene el potencial de ahorrar decenas, si no cientos de horas de desarrollador al mes, liberando equipos para pasar más tiempo construyendo y enviando cosas increíbles.

Presentamos npm ci para compilaciones más rápidas y confiables


Actualización 3: Como también señalan otras respuestas, el comando npm ci se introdujo en npm 5.7.0 como una forma adicional de lograr compilaciones rápidas y reproducibles en el contexto de CI. Consulte la documentation y el blog de npm para obtener más información.

Actualización 2: El problema para actualizar y aclarar la documentación es el problema # 18103 de GitHub .

Actualización 1: El comportamiento que se describe a continuación se solucionó en npm 5.4.2: el comportamiento previsto actualmente se describe en el problema de GitHub # 17979 .

Respuesta original: El comportamiento de package-lock.json se modificó en npm 5.1.0 como se discutió en el número 16866 . Al parecer, el comportamiento que observa es intencionado por npm a partir de la versión 5.1.0.

Eso significa que package.json puede superar a package-lock.json siempre que se encuentre una versión más nueva para una dependencia en package.json . Si desea fijar sus dependencias de manera efectiva, ahora debe especificar las versiones sin prefijo, por ejemplo, debe escribirlas como 1.2.0 lugar de ~1.2.0 o ^1.2.0 . Luego, la combinación de package.json y package-lock.json producirá compilaciones reproducibles. Para que quede claro: package-lock.json solo ya no bloquea las dependencias de nivel raíz.

Si esta decisión de diseño fue buena o no es discutible, hay una discusión en curso como resultado de esta confusión en GitHub en el número 17979 . (En mi opinión, es una decisión cuestionable; al menos el lock nombre ya no es cierto).

Una nota adicional: también hay una restricción para los registros que no admiten paquetes inmutables, como cuando extrae paquetes directamente desde GitHub en lugar de npmjs.org. Consulte esta documentación de bloqueos de paquetes para obtener más explicaciones.


Respuesta corta:

  • Cuando package-lock.json existe, anula package.json
  • Cuando package.json se modifica, anula el paquete-lock.json

Aquí hay un escenario que podría explicar cosas (verificado con NPM 6.3.0)

Declaras una dependencia en package.json como:

"depA": "^1.0.0"

Luego lo haces, npm install que generará un paquete-lock.json con:

"depA": "1.0.0"

Pocos días después, se lanza una versión menor más nueva de "depA", digamos "1.1.0", luego lo siguiente es cierto:

npm ci # respects only package-lock.json and installs 1.0.0 npm install # also, respects the package-lock version and keeps 1.0.0 installed # (i.e. when package-lock.json exists, it overrules package.json)

A continuación, actualice manualmente su package.json a:

"depA": "^1.1.0"

Luego vuelva a ejecutar:

npm ci # will try to honor package-lock which says 1.0.0 # but that does not satisfy package.json requirement of "^1.1.0" # so it would throw an error npm install # installs "1.1.0" (as required by the updated package.json) # also rewrites package-lock.json version to "1.1.0" # (i.e. when package.json is modified, it overrules the package-lock.json)