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.
Hay un problema abierto para esto en su página de github: https://github.com/npm/npm/issues/18712
Este problema es más grave cuando los desarrolladores utilizan diferentes sistemas operativos.
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
requierewidget ~v1.0.0
. Cuando npm lo instala, toma elwidget v1.0.0
. Más tarde, su compañero desarrollador (o compilación de CI) realiza una instalación npm y obtiene eltypescript v2.4.1
pero elwidget
se ha actualizado alwidget v1.0.1
. Ahora su módulo de nodo no está sincronizado. Esto es lopackage-lock.json
previenepackage-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
. Sitypescript
está bloqueado en2.4.1
en supackage-lock.json
, debería permanecer así hasta que se cambie. Y digamos que mañanatypescript
lanza la versión2.4.2
. Sinpm install
su sucursal y ejecutonpm 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.
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)