Node.js 22 Asciende a LTS - Soporte de require(ESM) y Resumen de Nuevas Funciones

2025.12.02

Vision General de Node.js 22 LTS

Node.js 22 ascendio a LTS (Long Term Support) en octubre de 2024. Con el nombre codigo “Jod”, recibira soporte activo hasta abril de 2027.

VersionLanzamientoInicio LTSFin
Node.js 182022/042022/102025/04
Node.js 202023/042023/102026/04
Node.js 222024/042024/102027/04
Node.js 242025/042025/102028/04

Recomendacion: Use versiones LTS en entornos de produccion

Soporte de ESM en require()

La caracteristica mas destacada de Node.js 22 es que ahora puede cargar modulos ES usando require() desde CommonJS.

// Paquete ESM (package.json: "type": "module")
// lib.mjs
export const greeting = 'Hello';
export function sayHello(name) {
  return `${greeting}, ${name}!`;
}
export default { greeting, sayHello };

// Ahora se puede cargar desde CommonJS
// app.cjs
const { greeting, sayHello } = require('./lib.mjs');
console.log(sayHello('World')); // Hello, World!

// Las exportaciones por defecto tambien estan disponibles
const lib = require('./lib.mjs');
console.log(lib.default.greeting); // Hello

Promocion desde Flag Experimental

# Antes de Node.js 22 (funcion experimental)
node --experimental-require-module app.js

# Node.js 22.12.0 y posterior (habilitado por defecto)
node app.js

# Para deshabilitar
node --no-experimental-require-module app.js

Precauciones

// ESM con top-level await no se puede usar con require
// async-lib.mjs
const data = await fetch('https://api.example.com/data');
export const config = await data.json();

// Esto causara un error
try {
  require('./async-lib.mjs'); // ERR_REQUIRE_ASYNC_MODULE
} catch (e) {
  console.error('No se puede usar require en modulos que contienen top-level await');
}

Cliente WebSocket (Incluido por Defecto)

// A partir de Node.js 22, WebSocket disponible sin librerias externas
const ws = new WebSocket('wss://echo.websocket.org');

ws.addEventListener('open', () => {
  console.log('Conexion completada');
  ws.send('Hello, WebSocket!');
});

ws.addEventListener('message', (event) => {
  console.log('Recibido:', event.data);
});

ws.addEventListener('close', () => {
  console.log('Desconectado');
});

ws.addEventListener('error', (error) => {
  console.error('Error:', error);
});

Integracion con Servidor HTTP

import { createServer } from 'http';
import { WebSocketServer } from 'ws';

const server = createServer();
const wss = new WebSocketServer({ server });

wss.on('connection', (ws, request) => {
  console.log('Nueva conexion:', request.url);

  ws.on('message', (message) => {
    // Broadcast
    wss.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(message.toString());
      }
    });
  });
});

server.listen(8080, () => {
  console.log('Servidor WebSocket ejecutandose en ws://localhost:8080');
});

Motor V8 12.4

Node.js 22 incluye V8 12.4, haciendo disponibles las ultimas funciones de JavaScript.

Array.fromAsync

// Crear array desde iterable asincrono
async function* asyncGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

const arr = await Array.fromAsync(asyncGenerator());
console.log(arr); // [1, 2, 3]

// Tambien puede procesar arrays de Promises
const promises = [
  fetch('/api/user/1'),
  fetch('/api/user/2'),
  fetch('/api/user/3'),
];

const responses = await Array.fromAsync(promises, (p) => p.then((r) => r.json()));

Nuevos Metodos de Set

const a = new Set([1, 2, 3, 4]);
const b = new Set([3, 4, 5, 6]);

// Union
console.log(a.union(b)); // Set {1, 2, 3, 4, 5, 6}

// Interseccion
console.log(a.intersection(b)); // Set {3, 4}

// Diferencia
console.log(a.difference(b)); // Set {1, 2}

// Diferencia simetrica
console.log(a.symmetricDifference(b)); // Set {1, 2, 5, 6}

// Verificacion de subconjunto
console.log(new Set([1, 2]).isSubsetOf(a)); // true
console.log(a.isSupersetOf(new Set([1, 2]))); // true

// Verificacion de conjuntos disjuntos
console.log(a.isDisjointFrom(new Set([7, 8]))); // true

Iterator Helpers

// Operaciones de transformacion en iteradores
function* numbers() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
}

// map, filter, take, etc. estan disponibles
const result = numbers()
  .filter((n) => n % 2 === 0)
  .map((n) => n * 2)
  .take(2)
  .toArray();

console.log(result); // [4, 8]

// drop: saltar los primeros elementos
const skipped = numbers().drop(2).toArray();
console.log(skipped); // [3, 4, 5]

// flatMap
function* nested() {
  yield [1, 2];
  yield [3, 4];
}
const flat = nested()
  .flatMap((arr) => arr)
  .toArray();
console.log(flat); // [1, 2, 3, 4]

// find
const found = numbers().find((n) => n > 3);
console.log(found); // 4

// some / every
console.log(numbers().some((n) => n > 3)); // true
console.log(numbers().every((n) => n > 0)); // true

SQLite Integrado (Experimental)

import { DatabaseSync } from 'node:sqlite';

// Base de datos en memoria
const db = new DatabaseSync(':memory:');

// Crear tabla
db.exec(`
  CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE
  )
`);

// Insertar datos
const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
insert.run('Alice', 'alice@example.com');
insert.run('Bob', 'bob@example.com');

// Ejecutar consulta
const select = db.prepare('SELECT * FROM users WHERE name = ?');
const user = select.get('Alice');
console.log(user); // { id: 1, name: 'Alice', email: 'alice@example.com' }

// Obtener todos los registros
const all = db.prepare('SELECT * FROM users').all();
console.log(all);

// Transaccion
const transfer = db.transaction((from, to, amount) => {
  db.prepare('UPDATE accounts SET balance = balance - ? WHERE id = ?').run(amount, from);
  db.prepare('UPDATE accounts SET balance = balance + ? WHERE id = ?').run(amount, to);
});

transfer(1, 2, 100);

Mejoras de Rendimiento

ElementoNode.js 20Node.js 22Mejora
Tiempo de inicio (Hello World)120ms85ms29% mas rapido
Servidor HTTP (req/sec)45,00052,00015% mas rapido
I/O de archivos (lectura de 1000 archivos)280ms230ms18% mas rapido
Procesamiento de streams320ms250ms22% mas rapido

Estabilizacion del Watch Mode

# Monitorear cambios de archivo y reiniciar automaticamente
node --watch server.js

# Monitorear solo rutas especificas
node --watch-path=./src --watch-path=./config server.js

# Excluir de monitoreo
node --watch --watch-preserve-output server.js
// Verificar estado de monitoreo programaticamente
import { watch } from 'node:fs/promises';

const ac = new AbortController();
const { signal } = ac;

(async () => {
  const watcher = watch('./src', { recursive: true, signal });
  for await (const event of watcher) {
    console.log(`${event.eventType}: ${event.filename}`);
  }
})();

// Detener monitoreo
// ac.abort();

Soporte Nativo de Patrones Glob

import { glob, globSync } from 'node:fs';

// API asincrona
const files = await glob('**/*.js', {
  cwd: './src',
  ignore: ['node_modules/**'],
});
console.log(files);

// API sincrona
const syncFiles = globSync('**/*.{ts,tsx}');
console.log(syncFiles);

// Tambien disponible a traves del modulo fs
import { promises as fs } from 'node:fs';
const matches = await fs.glob('src/**/*.test.ts');

Carga de Archivos de Variables de Entorno

# Cargar automaticamente archivo .env
node --env-file=.env app.js

# Soporte para multiples archivos
node --env-file=.env --env-file=.env.local app.js
# .env
DATABASE_URL=postgresql://localhost:5432/mydb
API_KEY=secret-key
NODE_ENV=development
// Acceder a variables de entorno
console.log(process.env.DATABASE_URL);
console.log(process.env.API_KEY);

Mejoras en el Test Runner

// test/user.test.js
import { describe, it, before, after, mock } from 'node:test';
import assert from 'node:assert/strict';

describe('User Service', () => {
  let mockDb;

  before(() => {
    mockDb = mock.fn(() => ({ id: 1, name: 'Test User' }));
  });

  after(() => {
    mock.reset();
  });

  it('should create a user', async () => {
    const user = await createUser({ name: 'Test User' });
    assert.strictEqual(user.name, 'Test User');
  });

  it('should validate email', () => {
    assert.throws(() => createUser({ email: 'invalid' }), /Invalid email/);
  });

  // Test de snapshot
  it('should match snapshot', async (t) => {
    const user = await getUser(1);
    t.assert.snapshot(user);
  });
});
# Ejecutar tests
node --test

# Con cobertura
node --test --experimental-test-coverage

# Solo archivos especificos
node --test test/user.test.js

Guia de Migracion

# Verificar version
node --version

# Si usa nvm
nvm install 22
nvm use 22
nvm alias default 22

# Verificar compatibilidad de dependencias
npx npm-check-updates --target minor

# Especificacion de motor en package.json
# "engines": { "node": ">=22" }

Enlaces de Referencia

← Volver a la lista