⚡ pnpm: El Ninja de la Eficiencia y el Espacio

“El ninja sabio no carga armas duplicadas. Un solo kunai perfectamente organizado vale más que mil esparcidos.” - Código de la Eficiencia

🎯 El Problema que Resuelve pnpm

Imagina que tienes 10 proyectos JavaScript en tu computadora. Todos usan React 18.

Con npm:

proyecto-1/node_modules/react/  (500 KB)
proyecto-2/node_modules/react/  (500 KB)
proyecto-3/node_modules/react/  (500 KB)
...
proyecto-10/node_modules/react/ (500 KB)

Total: 5 MB de React duplicado

Con pnpm:

~/.pnpm-store/react@18.2.0/      (500 KB, UNA SOLA VEZ)

proyecto-1/node_modules/react → enlace simbólico
proyecto-2/node_modules/react → enlace simbólico
proyecto-3/node_modules/react → enlace simbólico
...

Total: 500 KB + enlaces (casi 0 bytes)

Ahorro real en un proyecto promedio:

  • npm: 300 MB en node_modules/
  • pnpm: 30 MB (90% menos espacio)

📜 ¿Qué es pnpm?

pnpm (Performant npm) es un gestor de paquetes alternativo para JavaScript que:

  1. Ahorra espacio: Una sola copia de cada paquete en todo tu sistema
  2. Es más rápido: Instalaciones hasta 2x más veloces que npm
  3. Estructura estricta: Evita “phantom dependencies” (más sobre esto después)
  4. Compatible: Usa el mismo package.json y registry que npm

Instalación:

# Con npm (irónico pero funciona)
npm install -g pnpm

# Con Homebrew (macOS)
brew install pnpm

# Con script oficial
curl -fsSL https://get.pnpm.io/install.sh | sh -

# Verificar instalación
pnpm --version

🌳 Cómo Funciona el Store Global

npm (duplicación)

Cada proyecto tiene su propia copia completa:

~/proyectos/
├── proyecto-a/node_modules/lodash/    ← 500 KB
├── proyecto-b/node_modules/lodash/    ← 500 KB
└── proyecto-c/node_modules/lodash/    ← 500 KB

pnpm (deduplicación)

Un solo store global + enlaces simbólicos:

~/.pnpm-store/
└── lodash@4.17.21/                    ← 500 KB (UNA VEZ)

~/proyectos/
├── proyecto-a/node_modules/lodash → ~/.pnpm-store/lodash@4.17.21
├── proyecto-b/node_modules/lodash → ~/.pnpm-store/lodash@4.17.21
└── proyecto-c/node_modules/lodash → ~/.pnpm-store/lodash@4.17.21

Ventajas:

  • ✅ Ahorro masivo de espacio
  • ✅ Instalaciones más rápidas (no re-descarga)
  • ✅ Funciona offline si el paquete está en store

🚀 Comandos Básicos

pnpm usa la misma sintaxis que npm:

Instalar Paquetes

# Instalar dependencia
pnpm add express

# Instalar devDependency
pnpm add -D jest

# Instalar globalmente
pnpm add -g typescript

Eliminar Paquetes

pnpm remove lodash

Actualizar Paquetes

# Ver paquetes desactualizados
pnpm outdated

# Actualizar todos
pnpm update

# Actualizar uno específico
pnpm update react

Instalar Desde package.json

# Instalar todo (clonar proyecto)
pnpm install

# Instalar solo producción
pnpm install --prod

Ejecutar Scripts

pnpm run dev
pnpm run build
pnpm test  # 'run' es opcional para scripts comunes

💡 Ventajas Sobre npm

1. Estructura de node_modules Estricta

npm (problema):

// Tu package.json NO incluye 'lodash'
// Pero un paquete que instalaste SÍ lo usa

// Esto funciona pero NO DEBERÍA:
const _ = require('lodash');  // ✅ npm lo permite (phantom dependency)

pnpm (solución):

// Si no está en tu package.json, NO puedes usarlo
const _ = require('lodash');  // ❌ Error: Cannot find module 'lodash'

Por qué importa:

Si el paquete que usa lodash decide eliminarlo, tu código se rompe sin avisar con npm. Con pnpm, esto nunca pasa.

2. Velocidad de Instalación

Benchmark (proyecto promedio):

GestorPrimera instalaciónCon caché
npm45s18s
yarn40s12s
pnpm30s8s

3. Uso de Disco

Ejemplo real (15 proyectos JavaScript):

  • npm: 4.5 GB en node_modules/
  • pnpm: 600 MB en store + enlaces

Ahorro: 87%

4. Instalación Determinística

Siempre instala exactamente las mismas versiones, sin importar el orden.


🔍 pnpm vs npm: Comparación Directa

Característicanpmpnpm
Espacio en discoAltoBajo (90% ahorro)
VelocidadMediaAlta
Phantom deps✅ Permite❌ Bloquea
CompatibilidadUniversal99% compatible
MonoreposComplejoNativo
Curva aprendizajeBajaMuy baja (misma API)

🏢 Workspaces y Monorepos

pnpm tiene soporte nativo para monorepos (múltiples paquetes en un repo).

Estructura de Monorepo

mi-monorepo/
├── packages/
│   ├── app-web/
│   │   ├── package.json
│   │   └── src/
│   ├── app-mobile/
│   │   ├── package.json
│   │   └── src/
│   └── shared-utils/
│       ├── package.json
│       └── src/
├── pnpm-workspace.yaml
└── package.json

Configurar Workspace

Archivo pnpm-workspace.yaml:

packages:
  - 'packages/*'

Instalar dependencias para todo el monorepo:

pnpm install

Ejecutar comando en un paquete específico:

pnpm --filter app-web run dev
pnpm --filter shared-utils run test

Añadir dependencia a un paquete:

pnpm --filter app-web add react

Enlazar paquetes internos:

// packages/app-web/package.json
{
  "dependencies": {
    "shared-utils": "workspace:*"
  }
}

pnpm automáticamente enlaza packages/shared-utils en lugar de buscarlo en npm.


🎯 Cuándo Usar pnpm

✅ Usa pnpm si:

  • Trabajas con múltiples proyectos JavaScript
  • Espacio en disco es limitado
  • Quieres instalaciones más rápidas
  • Trabajas en monorepos
  • Te importa la estricta gestión de dependencias

⚠️ Considera npm/yarn si:

  • Trabajas en equipo que usa npm/yarn (compatibilidad)
  • Proyecto legacy con configuraciones específicas de npm
  • CI/CD tiene problemas con pnpm (raro pero posible)

🛠️ Comandos Avanzados de pnpm

Gestionar el Store Global

# Ver ubicación del store
pnpm store path

# Ver paquetes en store
pnpm store status

# Limpiar paquetes no usados (libera espacio)
pnpm store prune

Importar desde package-lock.json

# Convertir proyecto de npm a pnpm
pnpm import

Esto genera pnpm-lock.yaml desde package-lock.json.

Ejecutar con Filtros (Monorepos)

# Ejecutar test en todos los paquetes
pnpm -r test

# Ejecutar build solo en paquetes modificados
pnpm -r --filter=...HEAD build

# Ejecutar en paquetes que dependen de 'shared'
pnpm --filter=...shared build

💡 Migrar de npm a pnpm

Pasos para Proyecto Individual

# 1. Instalar pnpm globalmente
npm install -g pnpm

# 2. Eliminar node_modules y package-lock.json
rm -rf node_modules package-lock.json

# 3. Instalar con pnpm
pnpm install

# 4. Actualizar scripts de package.json
# (Opcional, solo si usabas 'npm run' en scripts personalizados)

# 5. Actualizar .gitignore
echo "node_modules/" >> .gitignore
echo "pnpm-lock.yaml" >> .gitignore  # Algunos lo versionan, otros no

Coexistencia con npm

Puedes usar ambos en proyectos diferentes:

# Proyecto A usa npm
cd proyecto-a
npm install

# Proyecto B usa pnpm
cd proyecto-b
pnpm install

Solo asegúrate de NO mezclarlos en el mismo proyecto.


⚠️ Limitaciones y Consideraciones

Phantom Dependencies en Proyectos Legacy

Si migras un proyecto viejo que dependía de phantom deps:

// Funcionaba con npm (mal diseño):
const _ = require('lodash');  // lodash NO está en package.json

// Con pnpm falla

Solución:

# Añade explícitamente la dependencia
pnpm add lodash

Compatibilidad con Scripts de npm

Algunos scripts de build pueden asumir estructura de node_modules/ de npm.

Solución:

# Forzar estructura plana (como npm)
pnpm install --shamefully-hoist

Esto sacrifica la estricta gestión pero mantiene compatibilidad.


🎯 Reto Ninja del Tema

Misión: Comprobar el ahorro de espacio de pnpm

  1. Crea dos proyectos de prueba:

    mkdir test-npm
    cd test-npm
    npm init -y
    npm install react lodash axios
    du -sh node_modules/  # Anota el tamaño
    
    cd ..
    mkdir test-pnpm
    cd test-pnpm
    pnpm init
    pnpm add react lodash axios
    du -sh node_modules/  # Compara el tamaño
  2. Crea un tercer proyecto con pnpm:

    mkdir test-pnpm-2
    cd test-pnpm-2
    pnpm init
    pnpm add react lodash
    du -sh node_modules/  # Debería ser casi instantáneo
  3. Verifica el store:

    pnpm store path
    ls -lh ~/.pnpm-store/v3/files/  # Ver paquetes compartidos
  4. Limpia paquetes no usados:

    pnpm store prune

Criterios de éxito:

  • ✅ Comprobaste el ahorro de espacio
  • ✅ La segunda instalación con pnpm fue más rápida
  • ✅ Entiendes cómo funciona el store global
  • ✅ Sabes cuándo usar pnpm vs npm

📚 Recursos Adicionales


Siguiente Pergamino: 4.6 yarn: El Orden del Monorepo

¿Probaste pnpm? Comparte tu ahorro de espacio en Discord con #pnpmNinja! ⚡🥷