⚡ 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:
- Ahorra espacio: Una sola copia de cada paquete en todo tu sistema
- Es más rápido: Instalaciones hasta 2x más veloces que npm
- Estructura estricta: Evita “phantom dependencies” (más sobre esto después)
- Compatible: Usa el mismo
package.jsony 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):
| Gestor | Primera instalación | Con caché |
|---|---|---|
| npm | 45s | 18s |
| yarn | 40s | 12s |
| pnpm | 30s | 8s |
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ística | npm | pnpm |
|---|---|---|
| Espacio en disco | Alto | Bajo (90% ahorro) |
| Velocidad | Media | Alta |
| Phantom deps | ✅ Permite | ❌ Bloquea |
| Compatibilidad | Universal | 99% compatible |
| Monorepos | Complejo | Nativo |
| Curva aprendizaje | Baja | Muy 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
-
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 -
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 -
Verifica el store:
pnpm store path ls -lh ~/.pnpm-store/v3/files/ # Ver paquetes compartidos -
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! ⚡🥷