📋 package.json: El Manifiesto del Proyecto y Versionado Semántico

“El pergamino del shinobi no solo describe sus técnicas, también establece las reglas para invocarlas.” - Código del Manifiesto Ninja

🎯 ¿Qué es package.json?

El archivo package.json es el corazón de todo proyecto JavaScript/Node.js:

  • Define metadatos del proyecto (nombre, versión, autor)
  • Lista dependencias (librerías que necesitas)
  • Configura scripts ejecutables
  • Establece reglas de versionado
  • Configura herramientas (ESLint, Babel, Jest)

Sin package.json:

  • No puedes instalar dependencias con npm
  • No hay forma de compartir tu proyecto
  • Cada desarrollador configura todo manualmente

📜 Anatomía Completa de package.json

{
  // ========== METADATOS ==========
  "name": "ninja-app",
  "version": "1.2.3",
  "description": "Aplicación ninja para gestionar misiones",
  "keywords": ["ninja", "missions", "tasks"],
  "author": "Abraham Pech <abraham@8devmx.com>",
  "license": "MIT",
  "homepage": "https://github.com/usuario/ninja-app#readme",
  "repository": {
    "type": "git",
    "url": "https://github.com/usuario/ninja-app.git"
  },
  "bugs": {
    "url": "https://github.com/usuario/ninja-app/issues"
  },

  // ========== PUNTO DE ENTRADA ==========
  "main": "index.js",
  "module": "dist/index.esm.js",
  "types": "dist/index.d.ts",

  // ========== SCRIPTS ==========
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "test": "jest",
    "lint": "eslint src/",
    "format": "prettier --write ."
  },

  // ========== DEPENDENCIAS ==========
  "dependencies": {
    "express": "^4.18.2",
    "react": "^18.2.0"
  },
  "devDependencies": {
    "jest": "^29.5.0",
    "eslint": "^8.40.0"
  },
  "peerDependencies": {
    "react": "^18.0.0"
  },

  // ========== CONFIGURACIÓN ==========
  "engines": {
    "node": ">=18.0.0",
    "npm": ">=9.0.0"
  },
  "private": false,
  "type": "module"
}

🎯 Campos Esenciales

1. name (Obligatorio)

El nombre del paquete. Debe ser único en npm si planeas publicarlo.

Reglas:

  • Minúsculas
  • Sin espacios (usa - o _)
  • Máximo 214 caracteres
{
  "name": "mi-libreria-ninja"  // ✅ Correcto
  "name": "Mi Librería"        // ❌ Espacios y mayúsculas
  "name": "@8devmx/utils"      // ✅ Scoped package (organización)
}

2. version (Obligatorio)

Versión del proyecto usando Semantic Versioning.

{
  "version": "1.2.3"
  // MAJOR.MINOR.PATCH
}

3. description

Breve descripción que aparece en npm search.

{
  "description": "Librería para autenticación ninja con JWT"
}

4. main

Archivo principal que se carga cuando alguien hace require('tu-paquete').

{
  "main": "index.js",        // CommonJS
  "module": "index.esm.js",  // ES Modules (para bundlers)
  "types": "index.d.ts"      // TypeScript definitions
}

5. scripts

Comandos personalizados ejecutables con npm run.

{
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "build": "webpack --mode production",
    "test": "jest --coverage"
  }
}

🚀 Scripts Poderosos

Scripts Pre y Post

npm ejecuta automáticamente scripts pre y post:

{
  "scripts": {
    "prebuild": "npm run lint",      // Se ejecuta ANTES de build
    "build": "webpack",
    "postbuild": "npm run deploy",   // Se ejecuta DESPUÉS de build

    "pretest": "npm run compile",
    "test": "jest",
    "posttest": "npm run coverage"
  }
}

Ejecutas:

npm run build

Sucede:

# 1. npm run prebuild  (lint)
# 2. npm run build     (webpack)
# 3. npm run postbuild (deploy)

Scripts Útiles para Proyectos Reales

{
  "scripts": {
    // Desarrollo
    "dev": "vite --port 3000",
    "dev:api": "nodemon --watch src src/server.js",
    "dev:db": "docker-compose up -d postgres",

    // Build
    "build": "tsc && vite build",
    "build:analyze": "vite build --mode analyze",
    "build:clean": "rm -rf dist && npm run build",

    // Testing
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",
    "test:e2e": "playwright test",

    // Calidad de código
    "lint": "eslint src/**/*.{js,ts,jsx,tsx}",
    "lint:fix": "eslint src/**/*.{js,ts,jsx,tsx} --fix",
    "format": "prettier --write \"src/**/*.{js,ts,jsx,tsx,json,css,md}\"",
    "type-check": "tsc --noEmit",

    // Deployment
    "predeploy": "npm run build",
    "deploy": "vercel --prod",

    // Utilidades
    "clean": "rm -rf node_modules dist .next",
    "reinstall": "npm run clean && npm install",
    "prepare": "husky install"  // Git hooks
  }
}

Pasar Argumentos a Scripts

{
  "scripts": {
    "test": "jest"
  }
}
# Pasar flags después de --
npm run test -- --coverage
# Ejecuta: jest --coverage

Ejecutar Múltiples Scripts en Paralelo

# Instalar npm-run-all
npm install -D npm-run-all
{
  "scripts": {
    "dev:client": "vite",
    "dev:server": "nodemon server.js",
    "dev": "npm-run-all --parallel dev:client dev:server"
  }
}

🔢 Versionado Semántico (Semver)

Estructura: MAJOR.MINOR.PATCH

Ejemplo: 2.5.7

  • 2 (MAJOR): Cambios incompatibles con versiones anteriores
  • 5 (MINOR): Nueva funcionalidad compatible hacia atrás
  • 7 (PATCH): Correcciones de bugs

Cuándo Incrementar Cada Número

# PATCH (1.0.0 → 1.0.1)
- Correcciones de bugs
- Optimizaciones de rendimiento
- Cambios en documentación

# MINOR (1.0.1 → 1.1.0)
- Nueva funcionalidad compatible
- Deprecar funciones (aún funcionan)
- Mejoras significativas

# MAJOR (1.1.0 → 2.0.0)
- Cambios incompatibles (breaking changes)
- Remover funciones deprecadas
- Cambiar APIs públicas

Rangos de Versiones

{
  "dependencies": {
    // Versión exacta
    "express": "4.18.2",

    // Caret (^): Compatible con minor/patch
    "react": "^18.2.0",
    // Permite: 18.2.0, 18.2.1, 18.3.0
    // NO permite: 19.0.0

    // Tilde (~): Compatible solo con patch
    "lodash": "~4.17.21",
    // Permite: 4.17.21, 4.17.22
    // NO permite: 4.18.0

    // Mayor o igual
    "axios": ">=1.0.0",

    // Rango específico
    "vue": ">=3.0.0 <4.0.0",

    // Cualquier versión (¡PELIGROSO!)
    "cowsay": "*",

    // Última versión
    "typescript": "latest"
  }
}

Operadores Comparados

// ^ (Caret) - Recomendado por defecto
"^1.2.3" → >=1.2.3 <2.0.0
"^0.2.3" → >=0.2.3 <0.3.0  (cuidado con 0.x)
"^0.0.3" → >=0.0.3 <0.0.4  (muy restrictivo)

// ~ (Tilde) - Para parches solamente
"~1.2.3" → >=1.2.3 <1.3.0
"~1.2"   → >=1.2.0 <1.3.0
"~1"     → >=1.0.0 <2.0.0

// Sin operador - Versión exacta
"1.2.3"1.2.3 (exactamente)

¿Cuál usar?

  • ^ (caret): Recomendado para la mayoría de paquetes
  • ~ (tilde): Cuando quieres solo bugfixes
  • Exacta: Solo para paquetes críticos o problemáticos

🎯 Tipos de Dependencias

dependencies

Paquetes que tu aplicación necesita en producción.

{
  "dependencies": {
    "express": "^4.18.2",
    "react": "^18.2.0",
    "lodash": "^4.17.21"
  }
}

devDependencies

Herramientas solo para desarrollo y testing.

{
  "devDependencies": {
    "jest": "^29.5.0",
    "eslint": "^8.40.0",
    "typescript": "^5.0.0",
    "nodemon": "^2.0.22"
  }
}

peerDependencies

Especifica qué versiones de paquetes debe tener el usuario de tu librería.

// Tu librería: react-ninja-ui
{
  "peerDependencies": {
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}

Significado: “Esta librería funciona con React 18+. El usuario debe instalarlo.”

optionalDependencies

Paquetes opcionales que no rompen la instalación si fallan.

{
  "optionalDependencies": {
    "fsevents": "^2.3.2"  // Solo funciona en macOS
  }
}

🛠️ Configuración Avanzada

Especificar Versión de Node.js

{
  "engines": {
    "node": ">=18.0.0",
    "npm": ">=9.0.0"
  }
}

npm avisará si el usuario tiene versión incorrecta.

Archivos a Publicar (si subes a npm)

{
  "files": [
    "dist/",
    "README.md",
    "LICENSE"
  ]
}

Solo estos archivos se subirán a npm (ignora src/, tests/, etc.).

Tipo de Módulo

{
  // Para usar ES Modules (import/export)
  "type": "module"

  // Para CommonJS (require/module.exports) - default
  "type": "commonjs"
}

Privado (no publicar en npm)

{
  "private": true
}

Previene publicación accidental con npm publish.


💡 Buenas Prácticas

1. Usa ^ para Dependencias

{
  "dependencies": {
    "express": "^4.18.2"  // ✅ Recibe bugfixes automáticamente
  }
}

2. Separa Correctamente dependencies y devDependencies

# Dependencia de producción
npm install react

# Dependencia de desarrollo
npm install -D jest

3. Versiona package-lock.json

# .gitignore
node_modules/
# NO ignores package-lock.json (debe estar versionado)

4. Especifica Versión de Node.js

{
  "engines": {
    "node": ">=18.0.0"
  }
}

5. Usa Scripts Descriptivos

{
  "scripts": {
    "dev": "vite",                    // ✅ Claro
    "start:dev:server": "nodemon",    // ❌ Muy largo
    "s": "webpack",                   // ❌ Críptico
  }
}

🎯 Reto Ninja del Tema

Misión: Crear un package.json profesional

  1. Inicializa proyecto:

    mkdir ninja-manifest
    cd ninja-manifest
    npm init -y
  2. Edita package.json con estos campos:

    {
      "name": "ninja-tasks",
      "version": "0.1.0",
      "description": "Gestor de misiones ninja",
      "author": "Tu Nombre",
      "license": "MIT",
      "scripts": {
        "start": "node index.js",
        "dev": "nodemon index.js",
        "test": "echo \"No tests yet\"",
        "prebuild": "echo \"Limpiando...\"",
        "build": "echo \"Building...\"",
        "postbuild": "echo \"Build completo\""
      },
      "dependencies": {
        "express": "^4.18.2"
      },
      "devDependencies": {
        "nodemon": "^2.0.22"
      },
      "engines": {
        "node": ">=18.0.0"
      }
    }
  3. Instala:

    npm install
  4. Prueba scripts:

    npm run build  # Verifica pre/post hooks
    npm run dev    # Nodemon debería funcionar

Criterios de éxito:

  • ✅ Todos los campos obligatorios presentes
  • ✅ Scripts pre/post funcionan
  • ✅ Dependencias instaladas correctamente
  • ✅ Usaste ^ en versiones

📚 Recursos Adicionales


Siguiente Pergamino: 4.8 Lockfiles y Reproducibilidad

¿Creaste tu manifiesto? Comparte tu package.json en Discord con #ManifiestoNinja! 📋🥷