1.3Módulos: CommonJS (require) frente a ES Modules
Lo esencial en 30 segundos
- Un módulo = un archivo, una responsabilidad: se exporta lo que se comparte, se importa lo que se necesita — base de la organización.
- CommonJS (histórico, omnipresente): module.exports para exportar, require() para importar — síncrono, sencillo, en todas partes en npm.
- ES Modules (estándar, futuro): export/import, activados vía .mjs o "type": "module" — recomendado para un proyecto nuevo, pero hay que leer los dos.
Minicaso hilado — Salim divide su aplicación en Argel
La aplicación de Salim cabe en un solo archivo de 500 líneas: las funciones de cálculo mezcladas con las lecturas de archivos, imposible de probar. La divide en tres módulos — cálculos, lectura de datos, visualización — cada uno exportando sus funciones: primero en CommonJS (module.exports/require) para entender, luego activa los ES Modules ("type": "module") para su nuevo proyecto. Cada módulo tiene una responsabilidad clara y se prueba por separado.
Continuación del caso 1.1-1.2 — Salim estructura su código tras el lenguaje y la asincronía.
1. CommonJS: module.exports y require()
Ningún programa serio cabe en un solo archivo: se divide en módulos (archivos con una responsabilidad, que se importan). El sistema histórico de Node es CommonJS: se exporta con module.exports (module.exports = { fn1, fn2 }) y se importa con require() (const truc = require('./monModule')). Síncrono, sencillo, presente en millones de paquetes npm. Un módulo local empieza por ./ o ../; un módulo nativo o npm se importa por su nombre (require('fs')).
Salim crea calculs.js con module.exports = { additionner, soustraire } y lo importa con require('./calculs'): su archivo de 500 líneas empieza a respirar.
2. ES Modules: export e import
Los ES Modules son la sintaxis estándar del lenguaje (la misma que en el navegador moderno): se exporta con export (export function fn() {}) y se importa con import (import { fn } from './autre.js'). Se activan nombrando sus archivos .mjs o — más habitual — añadiendo "type": "module" en el package.json. ESM está recomendado para un proyecto nuevo (estándar, futuro, coherente con el front-end).
Salim añade "type": "module" a su nuevo proyecto y pasa a import { additionner } from './calculs.js' — observando la extensión .js obligatoria en la ruta.
3. Entender los dos, dividir bien
CommonJS sigue omnipresente (código existente, tutoriales, paquetes): leerá muchísimo require/module.exports incluso escribiendo import/export. Mezclar ambos requiere precauciones (importar CommonJS desde ESM funciona, lo inverso es más delicado). Más allá de la sintaxis, lo esencial es el principio: dividir por responsabilidad, exportar una interfaz clara, nombrar los archivos explícitamente, evitar las dependencias circulares.
Salim nombra sus módulos calculs.js, donnees.js, affichage.js y solo exporta lo necesario: un desarrollador nuevo sabe dónde buscar sin preguntarle.
🔎 Ejemplo concreto — 🔎 Ejemplo concreto — Exportar e importar
Primero CommonJS, luego ES Modules: dos alternativas, un solo sistema por archivo.
// --- Alternativa A: CommonJS (archivo .js clásico) ---
// en calculs.js:
// module.exports = { additionner, soustraire };
// en app.js:
const calc = require("./calculs");
console.log(calc.additionner(2, 3));
Lectura: el módulo local se importa por su ruta en ./, el paquete o nativo por su nombre.
Lección: en ESM, el equivalente se escribe export function additionner + import { additionner } from './calculs.js' — con la extensión obligatoria.
Vocabulario de la sección
- Módulo
- Archivo separado con una responsabilidad, que exporta lo que pone a disposición e importa lo que necesita; base de la organización del código.
Ejemplo sencillo: Los calculs.js, donnees.js y affichage.js de Salim.
Lo que no es: un archivo único de 500 líneas que lo hace todo.
Reflejo: un archivo = una responsabilidad clara.
- CommonJS (CJS)
- Sistema histórico de módulos de Node: exportación con module.exports, importación con require(). Síncrono, sencillo, omnipresente en el ecosistema npm.
Ejemplo sencillo: El require('./calculs') de la primera división de Salim.
Lo que no es: la sintaxis import/export estándar del lenguaje.
Reflejo: leerlo con fluidez, incluso escribiendo ESM.
- ES Modules (ESM)
- Sistema estándar de módulos del lenguaje: exportación con export, importación con import. Activado vía .mjs o "type":"module" en package.json.
Ejemplo sencillo: El import { additionner } from './calculs.js' del nuevo proyecto de Salim.
Lo que no es: un require() en un archivo configurado en ESM.
Reflejo: proyecto nuevo = ESM, extensión explícita.
- require frente a import
- Las dos sintaxis de importación: require() (CommonJS) e import (ESM). Ambas coexisten en el código real, de ahí la necesidad de entender las dos.
Ejemplo sencillo: Salim lee require en los paquetes antiguos y escribe import en su proyecto.
Lo que no es: mezclarlos en un mismo archivo sin configuración adecuada.
Reflejo: un sistema por archivo, elegido con conocimiento.
- Ruta de módulo
- Local: empieza por ./ o ../ (archivos del proyecto). Nombre solo: módulo nativo (fs) o paquete npm de node_modules.
Ejemplo sencillo: El require('./calculs') local frente al require('fs') nativo en casa de Salim.
Lo que no es: require('calculs') sin ./ para un archivo del proyecto (no se encontrará).
Reflejo: ./ para el proyecto, nombre solo para el sistema y npm.
En la práctica — En la práctica — Organizar su código en módulos
- Cree un módulo que exporte funciones en CommonJS (module.exports = { fn1, fn2 }) e impórtelo con require('./monModule').
- Recree el mismo módulo en ESM (export function fn1() {}) e impórtelo con import (extensión .js explícita).
- Active ESM en un proyecto añadiendo "type": "module" al package.json, y observe que los .js se convierten en ES Modules.
- Importe un módulo nativo (fs) y un módulo local (por ./ruta) — detecte la diferencia de ruta.
Guion listo para decir — proponer la división en módulos (30 s)
«Este archivo tiene 500 líneas y tres oficios: propongo que lo dividamos en tres módulos — cálculos, datos, visualización — cada uno con sus exports. Podremos probar cada parte por separado y reutilizarlas en otro lugar.»
Para decir en la revisión de código; mostrar el plan de los tres módulos antes de dividir.
Modelo copiar-pegar — módulo CommonJS + uso
// calculs.js: se exporta lo que se comparte
function additionner(a, b) {
return a + b;
}
function soustraire(a, b) {
return a - b;
}
module.exports = { additionner, soustraire };
// app.js: se importa lo que se necesita
const calc = require("./calculs");
console.log(calc.additionner(2, 3));
console.log(calc.soustraire(5, 2));
Archivo único que dividir
Detectar las responsabilidades (cálculos, datos, visualización), extraer un módulo a la vez verificando con node en cada etapa — como Salim con sus 500 líneas.
Proyecto nuevo en Argel
Salim arranca en ESM ("type": "module"): misma sintaxis import/export que el front-end del equipo, un solo sistema que conocer.
Paquetes antiguos en require
Ante documentación en require: saber leerla y usarla tal cual, sin convertir todo el proyecto por ello.
Nomenclatura de equipo
Un nombre de archivo que dice lo que hace (donnees.js, validation.js): la estructura se convierte en documentación gratuita para el próximo desarrollador.
✓ Buenas prácticas
- Un módulo = una responsabilidad.
- Exportar solo lo necesario.
- Un sistema por archivo (sin mezclas).
✗ Errores frecuentes
- Mezclar require e import sin config.
- Olvidar ./ para un módulo local.
- Olvidar la extensión en ESM.
Puntos clave
- Dividir el código en MÓDULOS (archivos con una responsabilidad, que se exportan/importan) = fundamental para la organización y el mantenimiento.
- COMMONJS (histórico, omnipresente): exportación module.exports, importación require(). Síncrono, en millones de paquetes npm.
- ES MODULES (estándar, futuro): exportación export, importación import; activados vía .mjs o "type":"module" en package.json.
- Entender AMBOS (require E import coexisten); ESM recomendado para un proyecto nuevo. El PRINCIPIO prima sobre la sintaxis.
Reto 48h — aplíquelo mañana
Extraiga un módulo de su código (modelo anterior): module.exports + require('./...'), ejecútelo con node y luego conviértalo en export/import. 20 minutos bastan.
- Puedo explicar módulo, export e import.
- Sé distinguir require (CJS) de import (ESM).
- He dividido un módulo y lo he importado de ambas formas.
Preguntas frecuentes
CommonJS o ES Modules: ¿cuál elegir para mi proyecto?
Para un proyecto nuevo, ESM está recomendado: es el estándar oficial del lenguaje (no un invento de Node), coherente con el front-end (misma sintaxis en el navegador) y la dirección de futuro. Pero CommonJS sigue siendo una opción válida (sencillez, compatibilidad con el código existente) — y sobre todo, leerá muchísimo CommonJS (paquetes, tutoriales, código existente). ¿Por qué dos sistemas? Node creó CommonJS en 2009 porque JavaScript no tenía entonces ningún sistema de módulos; el lenguaje estandarizó los ES Modules en 2015 y Node los adoptó sin romper lo existente. De ahí la coexistencia que hay que conocer.
¿Cómo organizar bien mi código en módulos, más allá de la sintaxis?
Es una competencia de arquitectura independiente de require/import. Cada módulo tiene una responsabilidad clara (usuarios, base de datos, rutas, utilidades) — nada de cajones de sastre. Divida por funcionalidad, exporte una interfaz clara y mínima (lo público, el resto queda privado), nombre explícitamente (userService.js, validation.js), evite las dependencias circulares (A importa B que importa A) organizando jerárquicamente. Como Salim: tres módulos nombrados valen más que un archivo de 500 líneas.
¿Cómo importar un módulo local en CommonJS?