Node.js

Node

Tutorial Node: Scripts personalizados en package.json

Aprende a crear y gestionar scripts personalizados en package.json para automatizar tareas en proyectos Node.js de forma eficiente.

Aprende Node y certifícate

Scripts npm custom

Los scripts personalizados en npm permiten automatizar tareas específicas de tu proyecto Node.js mediante comandos definidos en el archivo package.json. Estos scripts van más allá de los comandos predeterminados como start o test, ofreciendo la flexibilidad de crear comandos personalizados que ejecuten cualquier tarea que necesites en tu flujo de desarrollo.

Definición de scripts personalizados

Para crear un script personalizado, simplemente añades una nueva entrada en la sección scripts de tu package.json. El nombre del script puede ser cualquier cadena válida, y el valor será el comando que se ejecutará:

{
  "name": "mi-proyecto-node",
  "version": "1.0.0",
  "scripts": {
    "dev": "node --watch app.js",
    "build": "node build.js",
    "clean": "rm -rf dist/",
    "backup": "node scripts/backup.js"
  }
}

Una vez definidos, puedes ejecutar estos scripts usando npm run seguido del nombre del script:

npm run dev
npm run build
npm run clean
npm run backup

Scripts para desarrollo y producción

Es común crear scripts diferenciados para distintos entornos. Por ejemplo, puedes tener un script para desarrollo que incluya opciones de depuración y otro para producción optimizado:

{
  "scripts": {
    "dev": "NODE_ENV=development node --inspect app.js",
    "prod": "NODE_ENV=production node app.js",
    "dev:watch": "NODE_ENV=development node --watch --inspect app.js",
    "start:cluster": "NODE_ENV=production node cluster.js"
  }
}

Los nombres descriptivos ayudan a identificar rápidamente el propósito de cada script. Usar prefijos como dev:, build: o test: facilita la organización cuando tienes muchos scripts.

Combinación de comandos

Los scripts npm pueden combinar múltiples comandos usando operadores del sistema. Esto resulta especialmente útil para crear flujos de trabajo complejos:

{
  "scripts": {
    "prebuild": "npm run clean",
    "build": "node build.js && npm run minify",
    "postbuild": "npm run copy-assets",
    "minify": "node scripts/minify.js",
    "copy-assets": "cp -r assets/ dist/assets/",
    "full-deploy": "npm run build && npm run test && npm run deploy"
  }
}

El operador && ejecuta el segundo comando solo si el primero termina exitosamente. También puedes usar || para ejecutar un comando alternativo si el primero falla, o ; para ejecutar comandos secuencialmente independientemente del resultado.

Scripts con herramientas externas

Los scripts personalizados pueden integrar herramientas externas instaladas como dependencias de desarrollo. Esto permite automatizar tareas como linting, formateo de código o análisis estático:

{
  "scripts": {
    "lint": "eslint src/",
    "lint:fix": "eslint src/ --fix",
    "format": "prettier --write src/**/*.js",
    "audit:security": "npm audit --audit-level moderate",
    "docs": "jsdoc src/ -d docs/",
    "analyze": "node --prof app.js"
  },
  "devDependencies": {
    "eslint": "^8.0.0",
    "prettier": "^3.0.0",
    "jsdoc": "^4.0.0"
  }
}

Scripts de utilidad del sistema

También puedes crear scripts que ejecuten comandos del sistema operativo para tareas de mantenimiento o configuración:

{
  "scripts": {
    "logs": "tail -f logs/app.log",
    "disk-usage": "du -sh node_modules/",
    "ports": "lsof -i :3000",
    "memory": "node -e \"console.log(process.memoryUsage())\"",
    "env-check": "node -e \"console.log(process.env.NODE_ENV || 'development')\""
  }
}

Organización de scripts complejos

Para proyectos grandes, es recomendable organizar scripts complejos en archivos separados dentro de una carpeta scripts/:

{
  "scripts": {
    "setup": "node scripts/setup.js",
    "migrate": "node scripts/migrate.js",
    "seed": "node scripts/seed-database.js",
    "generate": "node scripts/generate-config.js"
  }
}

Esto mantiene el package.json limpio y permite crear scripts más sofisticados con mejor manejo de errores y logging:

// scripts/setup.js
const fs = require('fs');
const path = require('path');

console.log('🚀 Configurando proyecto...');

// Crear directorios necesarios
const dirs = ['logs', 'uploads', 'temp'];
dirs.forEach(dir => {
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
    console.log(`✅ Directorio ${dir} creado`);
  }
});

// Copiar archivo de configuración
const configTemplate = path.join('config', 'config.template.json');
const configFile = path.join('config', 'config.json');

if (!fs.existsSync(configFile)) {
  fs.copyFileSync(configTemplate, configFile);
  console.log('✅ Archivo de configuración creado');
}

console.log('🎉 Configuración completada');

Los scripts personalizados se convierten en una herramienta fundamental para automatizar tareas repetitivas y estandarizar procesos en tu proyecto Node.js, mejorando la productividad del equipo de desarrollo.

Parámetros en scripts

Los scripts npm pueden recibir parámetros que permiten personalizar su comportamiento sin necesidad de crear múltiples scripts similares. Esta funcionalidad resulta especialmente útil cuando necesitas ejecutar el mismo comando base con diferentes opciones o configuraciones.

Paso de parámetros básicos

Para pasar parámetros a un script, utiliza -- seguido de los argumentos que quieres enviar. Todo lo que aparezca después de -- se pasará directamente al comando definido en el script:

{
  "scripts": {
    "start": "node app.js",
    "dev": "node --watch app.js"
  }
}
npm run start -- --port=8080
npm run dev -- --env=development --debug

En este caso, el comando real que se ejecuta sería node app.js --port=8080 y node --watch app.js --env=development --debug respectivamente.

Acceso a parámetros en Node.js

Dentro de tu aplicación Node.js, puedes acceder a estos parámetros mediante process.argv, que contiene un array con todos los argumentos pasados al proceso:

// app.js
console.log('Argumentos recibidos:', process.argv);

// Buscar parámetros específicos
const args = process.argv.slice(2);
const portArg = args.find(arg => arg.startsWith('--port='));
const port = portArg ? portArg.split('=')[1] : 3000;

console.log(`Servidor iniciando en puerto: ${port}`);

Una forma más elegante de manejar parámetros es crear una función helper que los procese:

// utils/args.js
function parseArgs() {
  const args = {};
  process.argv.slice(2).forEach(arg => {
    if (arg.startsWith('--')) {
      const [key, value] = arg.substring(2).split('=');
      args[key] = value || true;
    }
  });
  return args;
}

module.exports = { parseArgs };
// app.js
const { parseArgs } = require('./utils/args');

const config = parseArgs();
const port = config.port || 3000;
const debug = config.debug || false;

console.log(`Puerto: ${port}, Debug: ${debug}`);

Variables de entorno como parámetros

Los scripts también pueden utilizar variables de entorno para recibir configuración. Esto es especialmente útil para valores que no quieres exponer en la línea de comandos:

{
  "scripts": {
    "start": "node app.js",
    "start:prod": "NODE_ENV=production PORT=80 node app.js",
    "start:dev": "NODE_ENV=development PORT=3000 DEBUG=true node app.js"
  }
}

También puedes combinar variables de entorno con parámetros:

PORT=8080 npm run start -- --debug --verbose

Scripts parametrizados avanzados

Para casos más complejos, puedes crear scripts que acepten múltiples parámetros y los procesen de forma inteligente:

{
  "scripts": {
    "test": "node test-runner.js",
    "migrate": "node scripts/migrate.js",
    "backup": "node scripts/backup.js"
  }
}
// test-runner.js
const { parseArgs } = require('./utils/args');

const config = parseArgs();
const testFile = config.file || 'all';
const verbose = config.verbose || false;
const coverage = config.coverage || false;

console.log(`Ejecutando tests: ${testFile}`);
if (verbose) console.log('Modo verbose activado');
if (coverage) console.log('Generando reporte de cobertura');

// Lógica del test runner...
npm run test -- --file=auth --verbose --coverage

Parámetros con valores por defecto

Es una buena práctica definir valores por defecto para los parámetros más comunes, asegurando que tu aplicación funcione incluso sin parámetros específicos:

// config/defaults.js
const defaults = {
  port: 3000,
  host: 'localhost',
  env: 'development',
  logLevel: 'info'
};

function getConfig() {
  const args = parseArgs();
  return {
    port: args.port || process.env.PORT || defaults.port,
    host: args.host || process.env.HOST || defaults.host,
    env: args.env || process.env.NODE_ENV || defaults.env,
    logLevel: args.logLevel || process.env.LOG_LEVEL || defaults.logLevel
  };
}

module.exports = { getConfig };

Validación de parámetros

Para aplicaciones robustas, es importante validar los parámetros recibidos antes de utilizarlos:

// utils/validation.js
function validateConfig(config) {
  const errors = [];
  
  if (config.port && (isNaN(config.port) || config.port < 1 || config.port > 65535)) {
    errors.push('El puerto debe ser un número entre 1 y 65535');
  }
  
  if (config.env && !['development', 'production', 'test'].includes(config.env)) {
    errors.push('El entorno debe ser: development, production o test');
  }
  
  if (errors.length > 0) {
    console.error('❌ Errores de configuración:');
    errors.forEach(error => console.error(`  - ${error}`));
    process.exit(1);
  }
  
  return true;
}

module.exports = { validateConfig };

Scripts con ayuda integrada

Una práctica profesional es incluir información de ayuda en tus scripts cuando se pasan parámetros incorrectos o se solicita ayuda:

// app.js
const { parseArgs } = require('./utils/args');

const config = parseArgs();

if (config.help || config.h) {
  console.log(`
Uso: npm start [opciones]

Opciones:
  --port=<número>     Puerto del servidor (por defecto: 3000)
  --env=<entorno>     Entorno de ejecución (development|production)
  --debug             Activar modo debug
  --help, -h          Mostrar esta ayuda
  
Ejemplos:
  npm start -- --port=8080
  npm start -- --env=production --port=80
  `);
  process.exit(0);
}

Los parámetros en scripts proporcionan flexibilidad y reutilización, permitiendo que un mismo script se adapte a diferentes necesidades sin duplicar código ni configuraciones.

Aprende Node online

Otras lecciones de Node

Accede a todas las lecciones de Node y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a Node y certifícate

Ejercicios de programación de Node

Evalúa tus conocimientos de esta lección Scripts personalizados en package.json con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.