🟩 2.6 · Node.js y npm: JavaScript conquista el servidor

⏱ 5h 00min ⚡ 80 XP 🏅 Profesional Junior 📖 Backend FullStack
"Node.js no es mejor que PHP. Es DIFERENTE. Y conocer ambos te hace más versátil."

🎯 Objetivo del tema

Al terminar este tema serás capaz de: Al terminar este tema serás capaz de explicar qué es Node.js y por qué importa, instalar Node.js y npm, ejecutar scripts con Node, usar el sistema de módulos (CommonJS y ES Modules), y gestionar dependencias con package.json. Es el inicio del backend moderno con JavaScript.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

🗺️ Mapa del tema

En 2009, Ryan Dahl tuvo una idea revolucionaria: tomar el motor V8 de Chrome (que compila JavaScript a código máquina rapidísimo) y embebarlo en un programa que se ejecuta FUERA del navegador. Así nació Node.js: JavaScript en el servidor. Combinado con npm (el gestor de paquetes más grande del mundo), se convirtió en el ecosistema de desarrollo backend más usado después de PHP.

1. Qué es Node.js y por qué importa

V8 fuera del navegador: la revolución de 2009.

2. Instalación y primer script

Node, npm, y el clásico 'Hello, World' en consola.

3. Módulos: require vs import

CommonJS (antiguo) vs ES Modules (moderno). Cuándo usar cada uno.

4. npm: el gestor de paquetes más grande del mundo

package.json, instalar dependencias, y los comandos esenciales.

5. npx: ejecutar paquetes sin instalar

El atajo moderno para herramientas de línea de comandos.

6. Event Loop: el corazón de Node

Por qué Node es tan rápido con operaciones I/O.

2.6.1 Qué es Node.js y por qué importa

Node.js es un RUNTIME de JavaScript: un programa que ejecuta código JS fuera del navegador. Usa el mismo motor V8 de Chrome, así que es rapidísimo. Permite usar JavaScript tanto en el frontend (navegador) como en el backend (servidor), lo que simplifica el desarrollo full-stack.

📷 Imagen referencial: Ecosistema Node.js: motor V8 + libuv (async I/O) + módulos + npm (gestor de paquetes).
AspectoJavaScript en navegadorJavaScript en Node.js
EntornoNavegador (Chrome, Firefox, Safari).Sistema operativo (Windows, macOS, Linux).
MotorV8, SpiderMonkey, etc.V8 (el mismo de Chrome).
APIs disponiblesDOM, fetch, localStorage, etc.fs, http, path, process, etc.
Uso típicoInteractividad del usuario.Servidores, scripts, herramientas CLI.
⭐ Node.js es runtime, no lenguaje: Node.js NO es un lenguaje: es un entorno de ejecución. El lenguaje sigue siendo JavaScript. Lo que cambia es qué APIs tienes disponibles: en el navegador usas document y window; en Node usas fs (archivos) y http (servidores). Mismo lenguaje, distinto entorno.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.6.2 Instalación y primer script

Instalar Node.js instala 2 cosas: el runtime de Node (para ejecutar JS) y npm (Node Package Manager, el gestor de paquetes). Ambos vienen juntos. Después de instalar, puedes ejecutar JavaScript desde la terminal con `node archivo.js`.

// hola.js: tu primer script de Node
// Ejecutar: node hola.js en la terminal

const nombre = process.argv[2] || 'Mundo';
console.log(`Hola, ${nombre}!`);
console.log(`Versión de Node: ${process.version}`);
console.log(`Plataforma: ${process.platform}`);

// process.argv es como los argumentos de la terminal
// $ node hola.js Ana
// > Hola, Ana!
// > Versión de Node: v20.11.0
// > Plataforma: win32

Primer script de Node.js

⭐ REPL de Node: Node.js tiene un REPL (Read-Eval-Print Loop): escribe `node` en la terminal y te abre un ambiente interactivo donde puedes escribir JavaScript y ver el resultado inmediato. Es como la consola del navegador pero en tu terminal. Para salir: Ctrl+D o .exit.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.6.3 Módulos: require vs import

En Node.js, tu código se organiza en módulos. Hay 2 sistemas: CommonJS (con require, el antiguo) y ES Modules (con import, el moderno). El moderno es el estándar hoy. Saber ambos te permite leer código viejo y escribir código nuevo.

AspectoCommonJS (require)ES Modules (import)
Sintaxis de importconst x = require('./x')import x from './x.js'
Sintaxis de exportmodule.exports = xexport default x / export const y = ..
Extensión de archivo.js (cualquiera).js (con package.json 'type': 'module') O .mjs
CargaSíncrona.Asíncrona (top-level await posible).
Año2009 (original de Node).2015 (ES6 estándar oficial).
// CommonJS (antiguo):
// math.js
function sumar(a, b) { return a + b; }
module.exports = { sumar };
// app.js
const { sumar } = require('./math.js');

// ES Modules (moderno):
// math.js
export function sumar(a, b) { return a + b; }
// app.js
import { sumar } from './math.js';

// En package.json, para usar ES Modules:
{
  "type": "module",  // esto activa ES Modules en todo el proyecto
  "name": "mi-app",
  "version": "1.0.0"
}

CommonJS vs ES Modules en código

⭐ Configura 'type': 'module': Para usar ES Modules, agrega "type": "module" en tu package.json. O usa la extensión .mjs en los archivos específicos. Si no haces esto, Node asume CommonJS y tus import no funcionarán. Es el error #1 de principiantes con Node.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.6.4 npm: el gestor de paquetes más grande del mundo

npm viene con Node y es el registro de paquetes de JavaScript más grande del mundo: más de 2 millones de paquetes. Te permite instalar y gestionar dependencias (librerías) de tu proyecto. El archivo package.json es el corazón: describe tu proyecto y sus dependencias.

El archivo package.json

{
  "name": "mi-api",
  "version": "1.0.0",
  "description": "Mi primera API con Node.js",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "node --watch index.js",
    "test": "node test.js"
  },
  "dependencies": {
    "express": "^4.18.0",
    "cors": "^2.8.5"
  },
  "devDependencies": {
    "nodemon": "^3.0.0",
    "eslint": "^8.0.0"
  }
}

Anatomía de un package.json

Los 7 comandos de npm que usarás el 95%

ComandoQué haceCuándo usarlo
npm init -yCrea package.json inicial.Al empezar un proyecto nuevo.
npm installInstala todas las dependencias.Después de clonar un proyecto, o para instalar todo.
npm install nombreInstala un paquete como dependencia.Cuando necesitas una librería (express, axios, etc.).
npm install -D nombreInstala como devDependency.Para herramientas de desarrollo (nodemon, eslint).
npm uninstall nombreDesinstala un paquete.Cuando ya no lo necesitas.
npm run nombreEjecuta un script definido en package.json.Para correr tu app: npm run dev.
npm updateActualiza todas las dependencias.Periódicamente, para tener las últimas versiones.
⭐ package-lock.json siempre: SIEMPRE commitea tu package.json Y tu package-lock.json a Git. El package.json lista las dependencias, pero el package-lock.json fija las versiones EXACTAS. Sin él, un compañero que clone tu repo puede tener versiones diferentes y bugs inesperados. Es la diferencia entre un proyecto reproducible y uno caótico.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.6.5 npx: ejecutar paquetes sin instalar

npx es un atajo para ejecutar paquetes de npm sin tener que instalarlos globalmente. Es útil para herramientas de línea de comandos que solo usas ocasionalmente: create-react-app, vite, eslint, etc. Node 5.2+ lo trae integrado.

# ANTES: instalar globalmente y luego usar (versión vieja)
npm install -g create-react-app
create-react-app mi-proyecto

# AHORA: con npx, no necesitas instalar nada globalmente
npx create-react-app mi-proyecto
npx vite create mi-proyecto
npx eslint archivo.js
npx nodemon app.js
npx jest

# npx descarga el paquete, lo ejecuta, y lo borra. Cero instalación permanente.

npx: el atajo moderno

⭐ npx > npm install -g: Usa SIEMPRE npx para herramientas de scaffolding (create-*, vite create) y para correr herramientas sin contaminar tu sistema con instalaciones globales. Tu node_modules local tiene todo lo que tu proyecto necesita; npx evita el 'dependency hell' de paquetes globales.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

2.6.6 Event Loop: el corazón de Node

Node.js es de un solo hilo (como JavaScript en el navegador), pero maneja miles de conexiones simultáneas gracias al Event Loop: un ciclo que ejecuta código asíncrono sin bloquear el hilo principal. Es la magia que hace a Node perfecto para servidores con muchas conexiones I/O (bases de datos, archivos, APIs externas).

Cómo funciona (simplificado)

  • 1. Node recibe una petición (ej: leer un archivo).
  • 2. La manda a una operación asíncrona (fs.readFile) y SIGUE ejecutando otros callbacks.
  • 3. Cuando la operación termina, su callback se encola en el Event Loop.
  • 4. El Event Loop procesa los callbacks en orden, en el hilo principal.
  • 5. Mientras tanto, Node puede aceptar más peticiones.
// Ejemplo: operaciones async en paralelo
import fs from 'fs/promises';

// ❌ MAL: bloquea el hilo esperando
const data1 = fs.readFileSync('archivo1.txt', 'utf8');
const data2 = fs.readFileSync('archivo2.txt', 'utf8');
console.log(data1, data2);
// Lee UNO, espera, lee el otro, espera. Lento.

// ✅ BIEN: paralelo, no bloquea
const [data1, data2] = await Promise.all([
  fs.readFile('archivo1.txt', 'utf8'),
  fs.readFile('archivo2.txt', 'utf8'),
]);
console.log(data1, data2);
// Lanza las dos, espera AMBAS en paralelo. Rápido.

Event Loop: sync vs async

⭐ Node brilla en I/O, no en CPU: El Event Loop es lo que hace a Node perfecto para APIs con muchas operaciones I/O (consultas a BD, llamadas a APIs externas, lectura de archivos). Node NO es bueno para tareas que consumen mucha CPU (cálculos complejos, procesamiento de imágenes). Para eso usa Workers, o mejor: otro lenguaje. Conoce los límites de tu herramienta.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

📚 Contenido ampliado

Material adicional, referencias externas verificadas y ejemplos extendidos.

🤖 AI Mission

Node.js se aprende leyendo su documentación oficial y escribiendo código.

Misión: Crea un script en Node.js que lea 3 archivos JSON en paralelo usando fs/promises y Promise.all, combine los datos en un solo objeto, y lo escriba en un nuevo archivo. Pídele a la IA que revise tu código. Anota en tu cuaderno: ¿qué entiendes del Event Loop ahora que ves código async en acción?

Pasos sugeridos

  1. Crea una carpeta 'practica-node' y 3 archivos: usuarios.json, productos.json, pedidos.json (cada uno con 2-3 registros de ejemplo).
  2. Inicializa el proyecto: npm init -y. Configura 'type': 'module'.
  3. Crea combinar.js. Usa fs/promises y Promise.all para leer los 3 en paralelo.
  4. Combina los datos en un solo objeto resumen.
  5. Escribe el resultado en resumen.json.
  6. Ejecuta con node combinar.js. Verifica el archivo de salida.
  7. Pídele a la IA: 'Tengo este script Node que combina 3 archivos JSON. Sugiere 2 mejoras: manejo de errores, performance. NO me des código, dime la técnica y por qué.'
  8. Aplica las 2 mejoras. Vuelve a ejecutar.
  9. Anota en tu cuaderno, bajo 'Event Loop en acción': qué entendiste del async que antes no.

📓 Entregable: Captura de la ejecución, archivos JSON de entrada y salida, código de combinar.js, y media página de cuaderno con tu reflexión sobre async/Event Loop.

🚫 Errores típicos de razonamiento

Error 1: Usar require() con type='module' en package.json.
Por qué: Si tu package.json tiene 'type': 'module', Node espera sintaxis ES Modules (import/export). Si usas require(), Node lanza 'require is not defined'. Solución: o quitas 'type': 'module' y usas CommonJS, o conviertes todo a import/export. El estándar actual es ES Modules.
Error 2: Olvidar package-lock.json en el .gitignore.
Por qué: package-lock.json fija las versiones EXACTAS de cada dependencia. DEBE estar en Git para que todos los compañeros tengan las mismas versiones. Si lo pones en .gitignore, cada clone del repo puede tener versiones ligeramente distintas y bugs inesperados. Es la diferencia entre un proyecto reproducible y uno caótico.
Error 3: Hacer operaciones bloqueantes (sync) en un servidor Node.
Por qué: readFileSync, writeFileSync, execSync, etc. BLOQUEAN el hilo principal. Mientras se ejecuta una, TODO lo demás (incluidas otras peticiones HTTP) se queda esperando. En un servidor con 1000 usuarios concurrentes, eso es un desastre. Usa SIEMPRE las versiones async: readFile, writeFile, etc. Y en Express, usa async/await en los handlers.
Error 4: No usar async/await y caer en callback hell.
Por qué: Las APIs nativas de Node (sin promisify) usan callbacks. Si encadenas 3-4 operaciones async, terminas con el infierno de callbacks. Solución: usa fs/promises (que ya devuelve Promises) y async/await. Código limpio, legible, y moderno.
Error 5: Instalar dependencias con sudo (como administrador).
Por qué: Si haces 'sudo npm install ...', npm puede escribir en carpetas protegidas del sistema, lo cual es un riesgo de seguridad y puede causar conflictos de permisos. Si npm te pide permisos, es que hay un problema con tu configuración. Solución: usa nvm (Node Version Manager) para instalar Node en tu usuario, sin sudo. Es la práctica profesional.

🧪 Laboratorio práctico

Node.js se aprende haciendo: instalando, ejecutando, rompiendo y arreglando.

Laboratorio: Tu primer servidor HTTP nativo en Node.js

Objetivo: Crear un servidor HTTP nativo en Node.js (sin Express) que responda a 3 rutas: /, /api/usuarios (devuelve JSON), y /contacto (devuelve HTML). Practicarás: módulo http, routing manual, y respuesta con diferentes Content-Type.

Pasos

  1. Crea carpeta 'lab-node-http'. Inicializa: npm init -y. Agrega 'type': 'module'.
  2. Crea server.js. Importa el módulo http nativo de Node.
  3. Crea el servidor: const server = http.createServer((req, res) => { ... }).
  4. Implementa routing: if (req.url === '/') { ... } else if (req.url === '/api/usuarios') { ... }.
  5. Para '/': responde con HTML (Content-Type: text/html).
  6. Para '/api/usuarios': responde con JSON de un array de usuarios ficticios (Content-Type: application/json).
  7. Para '/contacto': responde con un formulario HTML simple.
  8. Para cualquier otra ruta: 404 con texto 'Página no encontrada'.
  9. Listen en puerto 3000: server.listen(3000).
  10. Prueba con curl o el navegador: localhost:3000/, /api/usuarios, /contacto.
  11. Agrega manejo de errores con try/catch en una ruta que falle.
  12. Haz commit: 'feat: servidor HTTP nativo con 3 rutas en Node.js'.

📓 Entregable: Capturas de las 3 rutas funcionando (HTML, JSON, formulario), código de server.js, y commit en Git.

📓 Tu cuaderno: Anota pseudocódigo, diagramas, errores que encontraste y respuestas a "explica sin código". La escritura manual refuerza tu razonamiento. Tu profesor puede pedirte que subas fotos de páginas específicas.