6 - Versionado y control de dependencias

Objetivo del tema

El objetivo es comprender las reglas del versionado semántico, interpretar los símbolos que npm admite en los rangos de dependencias, valorar el rol de package-lock.json y aprender a fijar versiones exactas cuando el proyecto lo requiere.

6.1 Reglas de versionado semántico (SemVer: major.minor.patch)

La mayoría de los paquetes publicados en npm siguen la especificación SemVer. Cada versión se expresa como major.minor.patch:

  • major: cambios incompatibles que pueden romper integraciones existentes.
  • minor: nuevas funcionalidades compatibles con versiones anteriores.
  • patch: correcciones de errores y mejoras internas sin nuevos features.

Cuando un paquete lanza la versión 2.4.1, el número 2 indica el major, 4 el minor y 1 el patch. Conocer esta convención ayuda a decidir cuándo actualizar y a comunicar expectativas al publicar tus propias bibliotecas.

6.2 Símbolos en dependencias (^, ~, *)

npm permite describir rangos de versiones en package.json usando operadores semánticos. Los más comunes son:

  • ^ (caret): admite actualizaciones que no modifiquen el número major. Ejemplo: ^4.18.0 permite 4.19.1, pero no 5.0.0.
  • ~ (tilde): bloquea minor y habilita cambios de patch. Ejemplo: ~4.18.0 acepta hasta 4.18.x pero no 4.19.0.
  • * o ausencia de versión: acepta cualquier lanzamiento. Se desaconseja en producción por su imprevisibilidad.
  • Comparadores (>=, <, <=, >): permiten rangos personalizados, por ejemplo >=4.0.0 <5.0.0.
{
  "dependencies": {
    "express": "^4.18.2",
    "mongoose": "~7.6.0",
    "winston": ">=3.10.0 <4.0.0"
  }
}

Elige el operador en función del riesgo que quieras asumir: rangos amplios ofrecen más actualizaciones automáticas, mientras que rangos estrictos aportan estabilidad.

6.3 package-lock.json y su importancia

package-lock.json captura las versiones exactas que npm instaló, incluidas las dependencias transitivas. Este archivo permite:

  • Garantizar instalaciones reproducibles entre miembros del equipo y entornos de despliegue.
  • Reducir tiempo de instalación, ya que npm utiliza la información cacheada sin volver a resolver rangos.
  • Facilitar auditorías de seguridad: herramientas como npm audit analizan el lock para detectar vulnerabilidades.

Nunca edites el archivo a mano; npm lo genera automáticamente. Cuando realices cambios en package.json, ejecuta npm install para que el lock se mantenga sincronizado. En entornos continuos, emplea npm ci para reinstalar desde cero respetando exactamente las versiones listadas.

6.4 Bloquear versiones exactas de dependencias

En algunos proyectos es imprescindible evitar actualizaciones automáticas. Puedes lograrlo de varias maneras:

  • Instala dependencias con --save-exact (o -E) para escribir la versión sin operador en package.json.
  • Configura el comportamiento por defecto con npm config set save-exact true.
  • Usa npm ci en despliegues para asegurarte de que solo se utilicen las versiones definidas en el lock.
  • Genera un archivo npm-shrinkwrap.json (comando npm shrinkwrap) si necesitas congelar dependencias también para consumidores de tu paquete.
npm install lodash@4.17.21 --save-exact
npm config set save-exact true
npm ci

Aunque fijar versiones evita sorpresas, recuerda revisar periódicamente el lock para aplicar parches de seguridad y documentar el proceso de actualización.

Resumen didáctico

Comprender SemVer y los operadores de versión, mantener package-lock.json alineado y saber cuándo bloquear dependencias te permite equilibrar estabilidad y evolución. Con estas bases, el equipo podrá actualizar con confianza y diagnosticar problemas derivados de cambios en terceros.