El autor del material, cuya traducción publicamos hoy, dice que uno de los problemas con los que los programadores tienen que lidiar es que su código funciona para ellos y le da errores a otra persona. Este problema, quizás uno de los más comunes, surge debido al hecho de que las diferentes dependencias que utiliza el programa están instaladas en los sistemas del creador y usuario del programa. Para combatir este fenómeno, existen los llamados archivos de bloqueo en los administradores de paquetes
yarn y
npm . Contienen información sobre las versiones exactas de las dependencias. El mecanismo es útil, pero si alguien está desarrollando un paquete que se planea publicar en npm, es mejor que no use archivos de bloqueo. Este material está dedicado a la historia de por qué esto es así.

Lo más importante en pocas palabras
Los archivos de bloqueo son extremadamente útiles cuando se desarrollan aplicaciones Node.js como servidores web. Sin embargo, si está hablando de crear una biblioteca o una herramienta de línea de comandos con el objetivo de publicar en npm, debe saber que los archivos de bloqueo en npm no se publican. Esto significa que si estos archivos se usan durante el desarrollo, entonces el creador del paquete npm y aquellos que usan este paquete usarán diferentes versiones de las dependencias.
¿Qué es un archivo de bloqueo?
El archivo de bloqueo describe el árbol de dependencia completo en la forma que adquirió durante el trabajo en el proyecto. Esta descripción también incluye dependencias anidadas. El archivo contiene información sobre versiones específicas de los paquetes utilizados. En el administrador de paquetes npm, dichos archivos se denominan
package-lock.json
, en yarn -
yarn.lock
. En ambos administradores, estos archivos se encuentran en la misma carpeta que
package.json
.
Así es como se
package-lock.json
.
{ "name": "lockfile-demo", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { "color-convert": "^1.9.0" } }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } } } }
Aquí hay un ejemplo de archivo
yarn.lock
. No está diseñado como
package-lock.json
, pero contiene datos similares.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0"
Ambos archivos contienen información de dependencia crítica:
- La versión exacta de cada dependencia instalada.
- Información de dependencia para cada dependencia.
- Información sobre el paquete descargado, incluida la suma de verificación utilizada para verificar la integridad del paquete.
Si todas las dependencias se enumeran en el archivo de bloqueo, ¿por qué entonces también agregan información sobre ellas a
package.json
? ¿Por qué se necesitan dos archivos?
Comparación de package.json y archivos de bloqueo
El propósito del campo de
dependencies
del archivo
package.json
es mostrar las dependencias del proyecto que deben instalarse para que funcione correctamente. Pero esto no incluye información sobre las dependencias de estas dependencias. La información de dependencia puede incluir versiones exactas de paquetes o un cierto rango de versiones especificadas de acuerdo con las reglas de
versiones semánticas . Cuando se utiliza el rango npm o hilo, se selecciona la versión más adecuada del paquete.
Supongamos que el
npm install
se ejecutó para instalar las dependencias de un determinado proyecto. Durante el proceso de instalación, npm recogió los paquetes adecuados. Si ejecuta este comando nuevamente, después de un tiempo, y si se lanzan nuevas versiones de dependencias durante este tiempo, puede ocurrir que la segunda vez se carguen otras versiones de los paquetes utilizados en el proyecto. Por ejemplo, si instala una dependencia, como
twilio
, utilizando el
npm install twilio
, la siguiente entrada puede aparecer en la sección de
dependencies
del archivo
package.json
:
{ "dependencies": { "twilio": "^3.30.3" } }
Si observa la
documentación de versiones semánticas de npm, puede ver que el signo
^
indica que cualquier versión del paquete que sea mayor o igual que 3.30.3 y menor que 4.0.0 es adecuada. Como resultado, si no hay un archivo de bloqueo en el proyecto y se lanza una nueva versión del paquete, el
npm install
o
yarn install
instalará automáticamente esta nueva versión del paquete. La información en
package.json
no se actualizará. Cuando se usan archivos de bloqueo, todo se ve diferente.
Si npm o yarn encuentra el archivo de bloqueo correspondiente, instalarán paquetes basados en este archivo y no en
package.json
. Esto es especialmente útil, por ejemplo, cuando se utilizan sistemas de Integración Continua (CI) en plataformas en las que necesita garantizar un funcionamiento uniforme del código y las pruebas en un entorno cuyas características se conocen de antemano. En tales casos, puede usar comandos o marcas especiales al invocar los administradores de paquetes apropiados:
npm ci # , package-lock.json yarn install --frozen-lock-file # , yarn.lock,
Esto es extremadamente útil si está desarrollando un proyecto como una aplicación web o servidor, ya que en un entorno de CI debe simular el comportamiento del usuario. Como resultado, si incluimos un archivo de bloqueo en el repositorio del proyecto (por ejemplo, creado usando herramientas git), podemos estar seguros de que cada desarrollador, cada servidor, cada sistema de creación de código y cada entorno de CI utiliza las mismas versiones dependencias
¿Por qué no hacer lo mismo al publicar bibliotecas u otras herramientas de software en el registro npm? Antes de responder esta pregunta, necesitamos hablar sobre cómo funciona el proceso de publicación de paquetes.
Proceso de publicación de paquetes
Algunos desarrolladores creen que lo que se publica en npm es exactamente lo que se almacena en el repositorio git, o en lo que se convierte el proyecto después de completar el trabajo en él. Este no es realmente el caso. Al publicar un paquete, npm descubre qué archivos publicar mediante el acceso a la clave de
files
en el archivo
package.json
y el archivo
.npmignore
. Si nada de esto se puede detectar, se
.gitignore
archivo
.gitignore
. Además, algunos archivos siempre se publican y otros nunca. Puede averiguar cuáles son estos archivos
aquí . Por ejemplo, npm siempre ignora la carpeta
.git
.
Después de eso, npm toma todos los archivos apropiados y los
empaqueta en un archivo
tarball
usando el comando
npm pack
. Si desea ver qué se
npm pack --dry-run
exactamente en dicho archivo, puede ejecutar el
npm pack --dry-run
en la carpeta del proyecto y ver la lista de materiales en la consola.
Npm pack --dry-run salida del comandoEl archivo
tarball
resultante se carga en el registro npm. Cuando ejecuta el
npm pack --dry-run
puede prestar atención al hecho de que si hay un archivo
package-lock.json
en el proyecto, no está incluido en el archivo tarball. Esto se debe al hecho de que este archivo, de acuerdo con las
reglas npm, siempre se ignora.
El resultado es que si alguien instala el paquete de otra persona, el archivo
package-lock.json
no estará involucrado. Lo que hay en este archivo que tiene el desarrollador del paquete no se tendrá en cuenta cuando alguien más lo instale.
Esto puede, por desafortunada coincidencia, conducir al problema del que hablamos al principio. En el sistema del desarrollador, el código funciona bien y en otros sistemas produce errores. Pero el hecho es que el desarrollador del proyecto y aquellos que lo usan usan diferentes versiones de los paquetes. ¿Cómo arreglarlo?
Rechazo de archivos de bloqueo y uso de tecnología retráctil
Primero debe evitar la inclusión de archivos de bloqueo en el repositorio del proyecto. Cuando use git, debe incluir lo siguiente en su archivo de proyecto
.gitignore
:
yarn.lock package-lock.json
La documentación de yarn dice que
yarn.lock
debe agregarse al repositorio incluso si se trata de desarrollar la biblioteca que planea publicar. Pero si desea que usted y los usuarios de su biblioteca trabajen con el mismo código, recomendaría incluir
yarn.lock
en el archivo
.gitignore
.
Puede deshabilitar la creación automática del archivo
package-lock.json
.npmrc
archivo
.npmrc
con los siguientes contenidos a la carpeta del proyecto:
package-lock=false
Cuando trabaje con hilo, puede usar el
yarn install --no-lockfile
, que le permite deshabilitar la lectura del archivo
yarn.lock
.
Sin embargo, el hecho de que
package-lock.json
archivo
package-lock.json
no significa que no podamos capturar información sobre dependencias y dependencias anidadas. Hay
otro archivo llamado
npm-shrinkwrap.json
.
En general, este
es el mismo archivo que
package-lock.json
, es creado por el
npm shrinkwrap
. Este archivo ingresa al registro npm cuando se publica el paquete.
Para automatizar esta operación, el
npm shrinkwrap
se puede agregar a la sección de descripción del script del archivo
package.json
como un script prepack. Puede lograr el mismo efecto utilizando el gancho de confirmación git. Como resultado, puede estar seguro de que en su entorno de desarrollo, en su sistema CI y los usuarios de su proyecto utilizan las mismas dependencias.
Vale la pena señalar que se recomienda utilizar esta técnica de manera responsable. Al crear archivos retráctiles, confirma versiones específicas de las dependencias. Por un lado, esto es útil para garantizar el funcionamiento estable del proyecto, por otro, puede evitar que los usuarios instalen parches críticos, que, de lo contrario, se harían automáticamente. De hecho, npm recomienda encarecidamente no utilizar archivos retráctiles al desarrollar bibliotecas, lo que limita su uso a algo así como sistemas de CI.
Encontrar información sobre paquetes y dependencias
Desafortunadamente, con toda la gran cantidad de información sobre la gestión de dependencias en la
documentación de npm, a veces es difícil navegar esta información. Si desea saber qué se instala exactamente durante la instalación de las dependencias o se empaqueta antes de enviar el paquete a npm, puede, con diferentes comandos, usar el
--dry-run
. El uso de esta bandera lleva al hecho de que el equipo no afecta el sistema. Por ejemplo, el
npm install --dry-run
realidad no instala las dependencias, y el
npm publish --dry-run
no inicia el proceso de publicación de paquetes.
Aquí hay algunos comandos similares:
npm ci --dry-run # , package-lock.json npm-shrinkwrap.json npm pack --dry-run # , npm install <dep> --verbose --dry-run #
Resumen
Mucho de lo que hablamos aquí se basa en los detalles de realizar varias operaciones usando npm. Estamos hablando de empaquetar, publicar, instalar paquetes, trabajar con dependencias. Y dado el hecho de que npm está en constante evolución, podemos decir que todo esto puede cambiar en el futuro. Además, la posibilidad de una aplicación práctica de las recomendaciones que se dan aquí depende de cómo el desarrollador del paquete perciba el problema de usar diferentes versiones de dependencias en diferentes entornos.
Esperemos que este material lo haya ayudado a comprender mejor cómo funciona el ecosistema de dependencia npm. Si desea profundizar aún más en esta pregunta,
aquí puede leer sobre las diferencias entre los comandos de
npm install
npm ci
y
npm install
.
Aquí puede averiguar qué hay exactamente en los
npm-shrinkwrap.json
package-lock.json
y
npm-shrinkwrap.json
.
Aquí está la página de documentación de npm donde puede averiguar qué archivos de proyecto están incluidos y no incluidos en los paquetes.
Estimados lectores! ¿Utiliza el archivo npm-shrinkwrap.json en sus proyectos?
