Skip to main content

¿Qué es package-lock.json y cómo funciona un archivo de bloqueo para paquetes de Yarn y npm?

Escrito por
Package Lock Files blog

14 de marzo de 2019

0 minutos de lectura

¿Qué es package-lock.json?

En este artículo hablaremos tanto del archivo de bloqueo de paquetes de npm, `package-lock.json`, como del archivo `_yarn.lock` de Yarn. Los archivos de bloqueo de paquetes funcionan como un manifiesto detallado de las dependencias de los proyectos: especifican la versión exacta de las dependencias que se deben instalar, así como las dependencias de esas dependencias y así sucesivamente, para abarcar todo el árbol de dependencias.

Un archivo de bloqueo de paquetes se incorpora por primera vez a un proyecto cuando se realiza una instalación nueva de sus dependencias. Durante la instalación, se calcula todo el árbol de dependencias y se guarda en el archivo de bloqueo, junto con metadatos sobre cada dependencia, como:

  • La versión del paquete que se debe instalar

  • Un hash de integridad que sirve para garantizar que el paquete no se haya manipulado

  • La ubicación del registro resuelta, que indica de dónde se obtuvo el paquete y de dónde se debe obtener en futuras instalaciones

Editor de código que muestra una entrada de package-lock para la dependencia acorn, incluida la versión 5.7.3, la URL del registro, el hash de integridad y el indicador dev.

¿Por qué necesitamos archivos de bloqueo?

Los archivos de bloqueo sirven para fijar o bloquear todas las versiones de todo el árbol de dependencias en el momento en que se crea el archivo. ¿Por qué es importante usar un archivo de bloqueo de paquetes y fijar las versiones de los paquetes?

Sin un archivo de bloqueo de paquetes, un administrador de paquetes como Yarn o npm resolverá en tiempo real la versión más reciente de un paquete durante la instalación de sus dependencias, en lugar de usar la versión prevista originalmente para ese paquete.

Diagrama de control de versiones semántico que muestra los componentes de número mayor, menor y de parche.

Por ejemplo, si un proyecto depende del paquete dummy-pkg: ^1.0.0, dos instalaciones ejecutadas en momentos distintos podrían obtener versiones diferentes de dummy-pkg. Esto puede ocurrir si un usuario instala `dummy-pkg` y obtiene la versión 1.0.0, y unos minutos después se publica la versión 1.0.1. Entonces, otro usuario que ejecute una instalación en el proyecto obtendría la versión 1.0.1 de `dummy-pkg` en lugar de la 1.0.0.

El uso de archivos de bloqueo garantiza que las instalaciones sean idénticas y reproducibles en todo el árbol de dependencias, entre usuarios —por ejemplo, los miembros de un equipo que trabajan juntos— y entre sistemas, como al ejecutar una compilación de CI.

¿Cómo funcionan los archivos de bloqueo?

En la mayor parte del ecosistema de npm se pueden identificar dos archivos de bloqueo de paquetes:

  • El archivo yarn.lock de Yarn

  • El archivo package-lock.json de npm

No hay nada como un buen diagrama de flujo para explicar cómo se usan estos dos archivos:

Diagrama que muestra cómo los archivos de bloqueo de npm y Yarn guían la instalación de paquetes, la publicación, el control de versiones y las compilaciones reproducibles.

Esta ilustración usa el archivo package-lock.json de npm, pero se puede reemplazar por yarn.lock en todos los casos. La única excepción es que el proceso de publicación del cliente npm no ignora automáticamente un archivo yarn.lock, por lo que se incluirá en el tarball del paquete a menos que se excluya explícitamente en el archivo .npmignore. Sin embargo, como vemos en el lado izquierdo de la ilustración, aunque ese archivo de bloqueo forme parte del paquete, no se usa para el usuario final que consume la biblioteca.

Ni Yarn ni npm tienen en cuenta los archivos de bloqueo de las dependencias transitivas; los administradores de paquetes los ignoran por completo. Solo se busca el árbol completo de dependencias del proyecto de nivel superior —donde se ejecuta una instalación— mediante un archivo de bloqueo, al que el administrador de paquetes considera el manifiesto de dependencias.

Archivos de bloqueo shrinkwrap

Nunca digas nunca. Hay un caso en el que existe un archivo de bloqueo especial que también se tiene en cuenta para las dependencias transitivas. El archivo npm-shrinkwrap.json fija el árbol de dependencias, igual que los demás archivos de bloqueo, pero el proceso de publicación de npm también confirma este archivo en el registro. Y lo más importante: cuando los usuarios finales consumen la biblioteca en una aplicación típica y ejecutan npm install, el archivo shrinkwrap de la biblioteca determina qué versiones instalar, en lugar de la resolución semver que se realiza durante la instalación.

Es importante tener en cuenta que Yarn y npm se comportan de manera distinta con los paquetes que incluyen un archivo npm-shrinkwrap.json:

  • npm siempre colocará las dependencias especificadas en npm-shrinkwrap.json en la carpeta node_modules/ del propio paquete y no intentará aplanar la estructura de directorios.

  • Yarn nunca tiene en cuenta npm-shrinkwrap.json y lo ignora por completo.

¿Para qué sirve un archivo shrinkwrap? Permite que quienes mantienen una biblioteca fijen y seleccionen sus propias dependencias para distribuir versiones conocidas. Sin embargo, requiere un mantenimiento cuidadoso de todo el árbol de dependencias. Además, si se usa un archivo shrinkwrap, no es necesario que haya ningún otro archivo de bloqueo en el control de código fuente. Un buen ejemplo de una biblioteca que adopta este enfoque es el conocido proyecto hapijs.

Archivos de bloqueo desactualizados

Los archivos de bloqueo se incorporan cuando los desarrolladores interactúan con un proyecto, por ejemplo, al agregar una dependencia o instalar las dependencias de un clon limpio del proyecto. Es habitual que los desarrolladores agreguen o eliminen dependencias durante el ciclo de desarrollo, pero ¿qué ocurre si modifican package.json y olvidan confirmar el archivo de bloqueo correspondiente?

Cuando el archivo package.json de un proyecto no está sincronizado con su archivo de bloqueo, los administradores de paquetes como npm y Yarn intentan conciliar las diferencias y generar un manifiesto nuevo. Aunque esto parezca conveniente, en realidad puede causar problemas si ocurre durante la CI.

Si el paso de compilación no falla cuando el archivo de bloqueo no coincide con las dependencias declaradas en package.json, los artefactos que se compilen o prueben podrían usar cualquier versión disponible en el momento de la compilación, lo que anula todos los beneficios de un archivo de bloqueo.

Por eso, se recomienda configurar los administradores de paquetes para que usen el archivo de bloqueo al instalar dependencias, por ejemplo:

$ yarn install --frozen-lock file
$ npm ci

Archivos de bloqueo para aplicaciones y bibliotecas

Las opiniones sobre cómo usar los archivos de bloqueo varían según si el proyecto es la aplicación principal o una biblioteca destinada a que la use una aplicación u otra biblioteca.

Hay consenso en que los proyectos de aplicaciones usen un archivo de bloqueo. En el caso de las bibliotecas, no tanto. ¿Por qué?

El principal argumento en contra de usar archivos de bloqueo en las bibliotecas es que provocan diferencias entre las dependencias que instalan quienes las consumen. Debido a estas diferencias, quienes mantienen los paquetes no detectarán compilaciones fallidas.

Sin embargo, si no se usa un archivo de bloqueo, las dependencias se resolverán únicamente durante la instalación y probablemente serán distintas para quienes mantienen el paquete y para quienes lo consumen.

En mi opinión, los proyectos de bibliotecas no son diferentes y deberían incluir un archivo de bloqueo para facilitar la colaboración entre los miembros del equipo y lograr compilaciones reproducibles.

Pero sugiero una mejora: si realmente te preocupa que las dependencias de tu biblioteca causen problemas a quienes la usan, puedes configurar dos compilaciones de CI distintas para detectar estos problemas:

  • Una que use el archivo de bloqueo del proyecto, como cualquier configuración de compilación normal.

  • La otra, que ignore el archivo de bloqueo del proyecto y resuelva las dependencias según sus versiones semver más recientes.

Este flujo te permite mantener compilaciones reproducibles y dependencias coherentes durante el desarrollo y, al mismo tiempo, detectar posibles cambios incompatibles para quienes consumen tu biblioteca. Y todo esto, mientras mantienes contentos a los desarrolladores de tu equipo.

Empieza con los desafíos de Capture the Flag

Aprende a resolver desafíos de captura la bandera con nuestro taller virtual introductorio a pedido.

Publicado en:

Leer más

Live Stream

Agentes de remediación, sin misterios: por qué solucionar es mejor que encontrar

Descubre cómo el agente de remediación de Snyk utiliza inteligencia de seguridad, análisis de explotabilidad y validación para convertir las vulnerabilidades en solicitudes de incorporación de cambios listas para fusionarse.

feature insights context
Blog

Dentro del compromiso de keyv en npm: malware preinstall, procedencia confiable y hooks de IDE

keyv 6.0.0 y diez versiones relacionadas de npm distribuyeron malware durante la instalación. Consulta las versiones afectadas, los hashes, los pasos de detección y el orden seguro para remediar el problema.

feature ai ide dark
Blog

Un primer vistazo a Evo Agentic AppSec: remediación agéntica y defensa contra código malicioso

Explora las primeras capacidades de Agentic AppSec de Snyk: un agente de remediación autónomo que corrige vulnerabilidades y una defensa contra código malicioso que bloquea paquetes riesgosos antes de que se publiquen.