Escena Viva es ya 1.0.0, con su etiqueta v1.0.0 en git, y su package.json está casi completo: nombre, versión, main, engines, dependencies, devDependencies. Queda un hueco, y es el que más se usa en el día a día: "scripts": { }. Ese objeto vacío es hoy el motivo de que, para arrancar el servidor, alguien tenga que recordar node src/servidor/servidor.js; para lanzar el informe de ocupación, node src/informes/ocupacion.js; y para la tubería de ventas, una ruta que solo conoce quien la escribió.
En esta lección convertimos scripts en la interfaz única del proyecto. Cuando terminemos, cualquier persona que clone el repositorio podrá escribir npm run y ver la lista completa de cosas que puede hacer, sin abrir un README ni preguntar a nadie. Y de paso resolveremos la pregunta que quedó pendiente en la lección 05-02: por qué "lint": "eslint src" funciona aunque nunca hayas instalado ESLint globalmente.
Contenido
- Qué es realmente el campo
scripts - Scripts predefinidos frente a scripts personalizados
- Los scripts de Escena Viva, uno a uno
- El
PATHextendido:node_modules/.bin - Paso de argumentos con
-- - Variables de entorno de los scripts
- Ganchos
preypost(y la advertencia depostinstall) - Encadenar comandos y sobrevivir a Windows
- ESLint y Prettier: qué resuelve cada uno
- Errores comunes y consejos
- Ejercicios
- Conclusión
- Qué es realmente el campo
scripts
scriptsscripts es un objeto donde cada clave es un nombre y cada valor es una línea de shell. Cuando ejecutas npm run <nombre>, npm:
- Busca la clave
<nombre>en elpackage.jsondel directorio actual. - Prepara un entorno especial (variables
npm_*y unPATHampliado, ya lo veremos). - Lanza esa línea con el shell del sistema (
/bin/shen POSIX,cmd.exeen Windows salvo configuración distinta). - Devuelve el código de salida del comando:
0es éxito, cualquier otro es fallo.
No hay magia adicional. No es un lenguaje nuevo: es shell. Lo valioso no es el mecanismo, sino la convención: todo el mundo espera encontrar ahí los comandos del proyecto.
| Comando | Qué hace |
|---|---|
npm run |
Lista todos los scripts disponibles con su contenido |
npm run <nombre> |
Ejecuta el script <nombre> |
npm run <nombre> -- <args> |
Ejecuta el script pasándole argumentos extra |
npm start |
Atajo de npm run start |
npm test |
Atajo de npm run test |
npm run <nombre> --silent |
Ejecuta ocultando el eco de npm |
- Scripts predefinidos frente a scripts personalizados
npm reconoce un puñado de nombres predefinidos que se pueden invocar sin la palabra run:
| Nombre | Invocación corta | Comportamiento especial |
|---|---|---|
start |
npm start |
Si no lo defines, npm intenta node server.js |
test |
npm test |
Si no lo defines, falla con un aviso |
stop |
npm stop |
Sin valor por defecto |
restart |
npm restart |
Ejecuta stop, luego restart, luego start |
Todo lo demás es personalizado y exige npm run. Es decir: npm dev no existe (npm intentará interpretarlo como un subcomando suyo y fallará), hay que escribir npm run dev.
Un detalle histórico que sigue vivo: si no defines start, npm busca server.js en la raíz. Escena Viva tiene su servidor en src/servidor/servidor.js, así que el valor por defecto no nos sirve y debemos declararlo explícitamente. Es lo correcto de todos modos: el script explícito documenta el punto de entrada.
- Los scripts de Escena Viva, uno a uno
Este es el package.json completo tras esta lección:
{
"name": "escena-viva",
"version": "1.0.0",
"description": "Plataforma de venta de entradas para eventos culturales",
"main": "src/servidor/servidor.js",
"type": "commonjs",
"private": true,
"engines": { "node": ">=24.5.0 <25" },
"scripts": {
"start": "node src/servidor/servidor.js",
"dev": "node --watch src/servidor/servidor.js",
"catalogo": "node src/catalogo.js",
"informe": "node src/informes/ocupacion.js",
"ventas": "node src/informes/tuberia-ventas.js",
"lint": "eslint src",
"format": "prettier --write \"src/**/*.js\"",
"format:check": "prettier --check \"src/**/*.js\"",
"comprobar": "npm run lint && npm run format:check",
"test": "node -e \"console.error('Sin pruebas todavia: llegan en el Modulo 9'); process.exit(1)\""
},
"dependencies": { "dotenv": "^17.2.1" },
"devDependencies": { "prettier": "^3.6.2" }
}Vamos comando a comando.
start
Arranca el servidor HTTP que construimos en el Módulo 4. Coincide con el campo main, y eso no es casualidad: main declara el punto de entrada del paquete, start declara cómo se ejecuta el proceso. Un servidor en producción se levanta con npm start (o directamente con node, ver el aviso más abajo).
dev
--watch es una bandera nativa de Node (estable desde Node 22) que reinicia el proceso cuando cambia cualquier fichero del que dependa el módulo cargado. Durante años esto exigía instalar nodemon como dependencia de desarrollo; hoy no hace falta ninguna dependencia externa, lo que encaja con la filosofía de Escena Viva: cero dependencias donde la plataforma ya sirve.
Diferencias que conviene conocer:
| Aspecto | node --watch |
nodemon |
|---|---|---|
| Instalación | Ninguna, viene con Node | Dependencia de desarrollo |
| Qué vigila | El grafo de módulos cargado | Patrones configurables de ficheros |
| Configuración | --watch-path, --watch-preserve-output |
nodemon.json con reglas ricas |
| Otros lenguajes | No | Sí (puede reiniciar cualquier comando) |
Para nuestro caso, --watch sobra y basta. Si algún día necesitas vigilar también datos/eventos.json, añade --watch-path=./datos.
catalogo
La CLI del catálogo del Módulo 1: imprime por stdout los tres eventos con sus sesiones. Ponerla en scripts la convierte en parte de la interfaz del proyecto en vez de un fichero suelto que hay que descubrir leyendo el árbol.
informe y ventas
informe calcula la ocupación (7 sesiones, aforo 3000, 1811 vendidas). ventas lanza la tubería de streams que lee datos/ventas.csv y produce el agregado por sesión. Los dos escriben datos por stdout y diagnósticos por stderr, la convención del curso, así que esto sigue funcionando:
El --silent es importante aquí: sin él, npm imprime dos líneas de cabecera (> [email protected] informe y el comando) que se colarían en tu fichero. npm las manda a stdout, no a stderr, así que si un script está pensado para redirigirse, acostúmbrate a --silent (o su forma corta -s).
lint
Esta es la promesa que hicimos en 05-02. ESLint no está instalado globalmente y sin embargo el script funcionará en cuanto añadas ESLint a devDependencies. La explicación completa está en el apartado 4.
format y format:check
--write reescribe los ficheros; --check solo comprueba y falla si algo no está formateado. El primero es para el desarrollo, el segundo para la integración continua, donde nunca quieres que una máquina modifique ficheros: quieres que te diga que están mal.
Fíjate en las comillas alrededor del patrón. Sin ellas, el shell POSIX expandiría src/**/*.js antes de que Prettier lo viera, y el resultado dependería de la configuración de globstar del shell y del sistema operativo. Con comillas, el patrón llega intacto a Prettier, que lo expande él mismo de forma idéntica en todas las plataformas. Es un detalle pequeño con consecuencias reales.
Los dos puntos en format:check no significan nada para npm: es solo una convención visual para agrupar variantes de un mismo script. npm run format:check es un nombre como cualquier otro.
comprobar
Un script de composición: no hace trabajo propio, encadena otros dos. Este es el patrón que conviene interiorizar: scripts pequeños de un solo propósito, más scripts que los combinan. Si mañana añadimos comprobación de tipos, se añade a la cadena sin tocar los demás.
test
Un test honesto. Hay dos malas alternativas:
- Dejar el
testpor defecto de npm (echo \"Error: no test specified\" && exit 1), que no dice nada útil. - Poner
"test": "exit 0"para que la CI pase en verde. Esto es mentir: el semáforo verde deja de significar algo.
Nuestro script escribe el motivo por stderr y sale con código 1. La CI fallará, que es exactamente lo que debe pasar en un proyecto 1.0.0 sin pruebas, y el mensaje dice dónde está la solución. En el Módulo 9 este script pasará a ser node --test test/ y el rojo se volverá verde con razón.
- El
PATH extendido: node_modules/.bin
PATH extendido: node_modules/.binAquí está la respuesta prometida. Muchos paquetes declaran ejecutables en su propio package.json:
Cuando npm instala un paquete con campo bin, crea un enlace en node_modules/.bin/. Tras instalar Prettier, el proyecto tiene:
Y cuando ejecutas npm run <algo>, npm antepone ese directorio al PATH del proceso hijo. Puedes verlo tú mismo:
Por eso "format": "prettier --write ..." encuentra prettier sin instalación global y sin escribir ./node_modules/.bin/prettier. Y por eso "lint": "eslint src" funcionará en cuanto ESLint esté en devDependencies.
flowchart LR A["npm run format"] --> B["PATH = node_modules/.bin : PATH original"] B --> C["shell busca 'prettier'"] C --> D["node_modules/.bin/prettier"] D --> E["node_modules/prettier/bin/prettier.cjs"]
Tres consecuencias prácticas:
- La versión que se ejecuta es la del proyecto, no la del sistema. Dos proyectos con Prettier 2 y Prettier 3 conviven sin conflictos.
- No hace falta
npxdentro de los scripts.npx prettierfunciona, pero añade una resolución innecesaria. Dentro descripts, escribe el binario a secas. - Si un comando falla con
command not founddentro de un script, casi siempre significa que falta el paquete en las dependencias, no que falte una instalación global.
- Paso de argumentos con
--
--Esto no hace lo que parece:
npm interpreta --sala como una opción suya (que no conoce) y no la pasa al script. El separador -- marca la frontera:
Ahora el comando ejecutado es node src/catalogo.js --sala="Sala Boveda" y los argumentos llegan a process.argv. Con un script así:
'use strict';
// Lee --sala del argv; devuelve null si no se ha pasado.
function leerSalaDeArgumentos(argumentos) {
const encontrado = argumentos.find((arg) => arg.startsWith('--sala='));
return encontrado ? encontrado.slice('--sala='.length) : null;
}
module.exports = { leerSalaDeArgumentos };El filtro funciona igual lo lances con node directamente o con npm run ... --. Regla mnemotécnica: todo lo que va antes de -- es para npm; todo lo que va después, para tu programa.
- Variables de entorno de los scripts
npm inyecta en el proceso hijo un conjunto de variables derivadas del manifiesto y de la configuración:
| Variable | Contenido |
|---|---|
npm_package_name |
escena-viva |
npm_package_version |
1.0.0 |
npm_lifecycle_event |
Nombre del script en ejecución |
npm_config_* |
Cualquier opción de configuración de npm |
PATH |
Extendido con node_modules/.bin |
Un uso real: que el servidor registre su versión al arrancar sin tener que leer el package.json en tiempo de ejecución.
// Dentro de src/servidor/servidor.js, al arrancar.
const version = process.env.npm_package_version ?? 'desconocida';
process.stderr.write(`Escena Viva ${version} escuchando en ${HOST}:${PUERTO}\n`);Ojo con la trampa: si alguien arranca con node src/servidor/servidor.js en vez de npm start, esa variable no existe. Por eso el ?? con un valor de reserva. Nunca hagas depender la lógica de negocio de una variable npm_*; úsalas solo para diagnósticos.
npm_lifecycle_event permite que un mismo fichero se comporte distinto según cómo lo hayan llamado, aunque suele ser preferible tener dos scripts explícitos.
Las opciones de configuración también llegan. Si ejecutas npm run informe --formato=csv, npm expone npm_config_formato=csv. Es un mecanismo real, pero prefiere -- y process.argv: es explícito, portable y funciona cuando ejecutas el script sin npm.
- Ganchos
pre y post
pre y postPara cualquier script x, npm ejecuta automáticamente prex antes y postx después, siempre que existan. Funciona con los predefinidos y con los personalizados:
"prestart": "node -e \"require('node:fs').accessSync('datos/eventos.json')\"",
"start": "node src/servidor/servidor.js"Si el fichero de datos no existe, prestart falla, y npm no ejecuta start. Un fallo temprano y claro en lugar de un servidor arrancado que revienta en la primera petición.
Los ganchos más conocidos son los del ciclo de instalación:
| Gancho | Cuándo se dispara |
|---|---|
preinstall |
Antes de instalar dependencias |
install / postinstall |
Después de instalarlas |
prepare |
Tras npm install local y antes de npm publish |
prepublishOnly |
Solo antes de publicar |
La advertencia de seguridad
postinstall es potente y por eso es peligroso. Cuando instalas un paquete, su postinstall se ejecuta en tu máquina con tus permisos, sin preguntarte nada. Puede leer tu ~/.npmrc (donde vive tu token de npm), tus variables de entorno, tus claves SSH.
Esto no es teoría: es el vector habitual de los ataques a la cadena de suministro. Un mantenedor con la cuenta comprometida publica una versión de parche con un postinstall malicioso, y miles de máquinas lo ejecutan en horas.
Medidas inmediatas, que ampliaremos en la lección 05-06:
- En CI y producción,
npm ci --ignore-scriptscuando el proyecto lo tolere. - Revisar los
postinstallde las dependencias nuevas antes de aceptarlas. - No guardar secretos en el entorno de la máquina que instala paquetes.
En tus propios scripts, postinstall está bien para tareas del proyecto (crear un directorio, generar un fichero derivado). El problema es el código ajeno, no el mecanismo.
- Encadenar comandos y sobrevivir a Windows
Los operadores del shell funcionan tal cual:
| Operador | Significado |
|---|---|
a && b |
Ejecuta b solo si a termina con código 0 |
a || b |
Ejecuta b solo si a falla |
a ; b |
Ejecuta b siempre |
a & b |
Ejecuta ambos en paralelo (no en cmd.exe) |
&& es el que quieres el 95 % de las veces: encadena y se detiene en el primer fallo. || sirve para valores de reserva: "informe": "node src/informes/ocupacion.js || echo 'informe no disponible' 1>&2".
La portabilidad es el problema real. Estas cosas rompen en Windows:
| Construcción POSIX | Problema en Windows | Solución |
|---|---|---|
rm -rf dist |
rm no existe |
node:fs o el paquete rimraf |
NODE_ENV=produccion node x.js |
Sintaxis no válida en cmd |
cross-env |
cmd1 & cmd2 (paralelo) |
& es secuencial |
npm-run-all --parallel |
cat fichero | node x.js |
Comportamiento distinto | Leer el fichero desde Node |
| Comillas simples | cmd.exe no las interpreta |
Comillas dobles escapadas |
Nuestros scripts de Escena Viva son deliberadamente portables: solo invocan node, eslint y prettier, y usan comillas dobles escapadas. Si algún día necesitas variables de entorno en línea:
Regla general: si un script empieza a parecerse a un programa, escríbelo como un programa en scripts/ y llámalo con node. JavaScript es portable; el shell no.
- ESLint y Prettier: qué resuelve cada uno
Se confunden a menudo y no compiten:
| ESLint | Prettier | |
|---|---|---|
| Pregunta que responde | ¿Este código tiene problemas? | ¿Este código está bien presentado? |
| Detecta | Variables sin usar, await en bucles, promesas sin capturar |
Nada semántico |
| Modifica | Solo lo que sabe arreglar (--fix) |
Todo el formato, siempre |
| Discutible | Sí, cada regla es una decisión de equipo | No, esa es la gracia |
La configuración moderna es simple: Prettier manda en el formato, ESLint manda en la corrección, y se desactivan en ESLint las reglas de estilo que chocarían con Prettier. Con el formato fuera de la conversación, las revisiones de código dejan de discutir comillas y hablan de lo que importa.
Para Escena Viva, ESLint entraría así:
Y el script "lint": "eslint src" empieza a funcionar sin más, gracias al PATH del apartado 4. La configuración de reglas es un tema en sí mismo y no la desarrollamos aquí: lo relevante para esta lección es que la herramienta se invoca desde scripts y vive en devDependencies.
Errores Comunes y Consejos
- Escribir
npm dev. Solostart,test,stopyrestartprescinden derun. Para el resto,npm run dev. - Olvidar el
--al pasar argumentos.npm run catalogo --sala=Xno llega a tu programa;npm run catalogo -- --sala=Xsí. - Redirigir sin
--silent. Las cabeceras de npm van a stdout y contaminan el fichero de salida. - Poner
"test": "exit 0". Un verde falso es peor que un rojo honesto: destruye la confianza en la CI. - Scripts gigantes de cinco comandos encadenados. Divide en scripts pequeños y compón con
&&. Se depuran mejor y se reutilizan. - Asumir bash.
shno esbashycmd.exeno es ninguno de los dos. Si dudas, mueve la lógica a un fichero.js. - Depender de
npm_package_versionen la lógica. Solo existe si se arrancó con npm. Úsala para diagnósticos, con valor de reserva. - Consejo: ejecuta
npm runsin argumentos al entrar en un proyecto ajeno. Es la documentación más fiable que vas a encontrar, porque si estuviera desactualizada, no funcionaría. - Consejo: nombra los scripts por lo que hacen para el negocio (
informe,ventas,catalogo), no por la herramienta que usan. La herramienta cambiará; la intención, no.
Ejercicios
Ejercicio 1: un script verificar-datos con gancho
Añade a Escena Viva un script verificar-datos que compruebe que datos/eventos.json existe, es JSON válido y contiene exactamente 3 eventos con 7 sesiones en total. Debe imprimir el resumen por stdout y salir con código 1 si algo falla. Engánchalo para que se ejecute automáticamente antes de informe.
Ejercicio 2: argumentos y --
Modifica src/catalogo.js para aceptar --sala=<nombre> y filtrar las sesiones de esa sala. Comprueba que funciona tanto con node directo como con npm run. Explica por qué una de las dos formas necesita --.
Ejercicio 3: composición y portabilidad
Diseña un script publicar-informes que ejecute comprobar, luego informe y luego ventas, deteniéndose al primer fallo. Después, revisa esta propuesta de un compañero y di qué tres cosas romperán en Windows:
"publicar-informes": "rm -rf salida && mkdir salida && NODE_ENV=prod node src/informes/ocupacion.js > salida/ocupacion.txt"Soluciones
Solución 1
// src/utiles/verificar-datos.js
'use strict';
const fs = require('node:fs');
const { RUTA_EVENTOS } = require('../config/rutas.js');
const EVENTOS_ESPERADOS = 3;
const SESIONES_ESPERADAS = 7;
// Lee el fichero semilla y valida su forma; lanza si algo no cuadra.
function verificarDatos() {
const crudo = fs.readFileSync(RUTA_EVENTOS, 'utf8');
const eventos = JSON.parse(crudo);
if (!Array.isArray(eventos)) {
throw new Error('eventos.json no contiene un array');
}
const totalSesiones = eventos.reduce((suma, ev) => suma + ev.sesiones.length, 0);
if (eventos.length !== EVENTOS_ESPERADOS || totalSesiones !== SESIONES_ESPERADAS) {
throw new Error(
`Se esperaban ${EVENTOS_ESPERADOS} eventos y ${SESIONES_ESPERADAS} sesiones; ` +
`hay ${eventos.length} y ${totalSesiones}`
);
}
return { eventos: eventos.length, sesiones: totalSesiones };
}
if (require.main === module) {
try {
const resumen = verificarDatos();
process.stdout.write(`Datos correctos: ${resumen.eventos} eventos, ${resumen.sesiones} sesiones\n`);
} catch (error) {
process.stderr.write(`Datos invalidos: ${error.message}\n`);
process.exit(1);
}
}
module.exports = { verificarDatos };"verificar-datos": "node src/utiles/verificar-datos.js",
"preinforme": "npm run verificar-datos --silent"El gancho preinforme corta la cadena antes de que informe intente trabajar con datos corruptos.
Solución 2
// Fragmento de src/catalogo.js
const filtroSala = leerSalaDeArgumentos(process.argv.slice(2));
const sesionesVisibles = filtroSala
? sesiones.filter((sesion) => sesion.sala === filtroSala)
: sesiones;La forma con npm run necesita -- porque npm consume los argumentos que empiezan por -- como opciones propias. Con node no hay intermediario: todo lo posterior al fichero va directo a process.argv.
Solución 3
Los tres problemas de la propuesta del compañero en Windows:
rm -rfno existe encmd.exe; hay que usarnode -e "fs.rmSync('salida', { recursive: true, force: true })"orimraf.NODE_ENV=prod comandono es sintaxis válida encmd.exe; requierecross-env.mkdir salidafalla si el directorio ya existe con distinto comportamiento según el shell; convienefs.mkdirSync(..., { recursive: true }).
Además, la redirección > sin --silent metería las cabeceras de npm dentro de salida/ocupacion.txt.
Conclusión
El package.json de Escena Viva ya no tiene huecos. scripts es hoy la interfaz única del proyecto: npm start levanta el servidor, npm run dev lo recarga con node --watch sin depender de nadie, npm run catalogo, npm run informe y npm run ventas exponen el trabajo de los módulos 1 y 3, npm run comprobar compone linting y formato, y npm test falla con un mensaje honesto que apunta al Módulo 9.
Por el camino has entendido el mecanismo que lo sostiene: npm ejecuta shell con un PATH que empieza en node_modules/.bin, y por eso las herramientas del proyecto se invocan por su nombre sin instalación global. Sabes separar los argumentos de npm de los tuyos con --, aprovechar npm_package_version para diagnósticos, encadenar con && sin sacrificar la portabilidad, y desconfiar del postinstall del código ajeno.
En la lección siguiente, Creación y Publicación de Paquetes, cambiamos de lado del mostrador. Hasta ahora hemos consumido paquetes; ahora vamos a publicar uno. Extraeremos src/utiles/formato.js —con formatearPrecio, formatearFecha y generarCodigoEntrada— a un paquete propio, @escena-viva/formato, y veremos cómo se decide qué es API pública con exports, qué se sube realmente con files, cómo se comprueba el tarball con npm pack antes de que sea tarde, y por qué despublicar un paquete es casi imposible.
Curso de Node.js: De Principiante a Avanzado
Módulo 1: Introducción a Node.js
- ¿Qué es Node.js?
- Instalación y Configuración del Entorno
- Tu Primer Programa en Node.js
- El REPL de Node.js
- JavaScript Moderno para Node.js
- El Proyecto del Curso: la Plataforma Escena Viva
Módulo 2: Conceptos Básicos
- Arquitectura de Node.js
- El Bucle de Eventos (Event Loop)
- Callbacks y Programación Asíncrona
- Promesas y async/await
- Eventos y EventEmitter
- Módulos CommonJS y require()
- Módulos ES e Interoperabilidad
Módulo 3: Sistema de Archivos y E/S
- Lectura y Escritura de Archivos
- El Módulo fs a Fondo
- Rutas Multiplataforma con el Módulo path
- Trabajando con Streams
- Streams de Transformación y pipeline
- Buffers y Datos Binarios
Módulo 4: HTTP y Servidores Web
- Creando un Servidor HTTP Simple
- Manejo de Solicitudes y Respuestas
- Enrutamiento Manual
- Sirviendo Archivos Estáticos
- Recibiendo Datos: Cuerpos de Petición y JSON
- Consumiendo APIs Externas desde Node.js
Módulo 5: NPM y Gestión de Paquetes
- Introducción a NPM y package.json
- Instalación y Uso de Paquetes
- Versionado Semántico y package-lock
- Scripts de npm y Automatización del Proyecto
- Creación y Publicación de Paquetes
- Seguridad y Mantenimiento de Dependencias
Módulo 6: Framework Express.js
- Introducción a Express.js
- Configuración de una Aplicación Express
- Enrutamiento en Express
- Middleware
- Middleware de Terceros Esenciales
- Validación de Datos de Entrada
- Manejo de Errores
Módulo 7: Bases de Datos y ORMs
- Introducción a las Bases de Datos
- Usando MongoDB con Mongoose
- Operaciones CRUD
- Relaciones, Poblado y Consultas Avanzadas
- Usando Bases de Datos SQL con Sequelize
- Migraciones, Transacciones y Datos de Prueba
Módulo 8: Autenticación y Autorización
- Introducción a la Autenticación
- Registro de Usuarios y Hash de Contraseñas
- Sesiones y Cookies con Passport.js
- Autenticación con JWT
- Control de Acceso Basado en Roles
- Buenas Prácticas de Seguridad en APIs
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias con Mocha y Chai
- Dobles de Prueba con Sinon
- Pruebas de Integración
- Cobertura y Automatización de las Pruebas
- Depuración de Aplicaciones Node.js
Módulo 10: Temas Avanzados
- El Módulo Cluster
- Hilos de Trabajo (Worker Threads)
- Caché y Colas de Trabajo con Redis
- Optimización del Rendimiento
- Construcción de APIs RESTful
- GraphQL con Node.js
Módulo 11: Despliegue y DevOps
- Configuración y Variables de Entorno
- Registro y Monitorización en Producción
- Usando PM2 para la Gestión de Procesos
- Empaquetado con Docker
- Desplegando en Heroku y Otras PaaS
- Integración y Despliegue Continuos
