Módulos en Node.js
En Node.js, los módulos son bloques de código independientes que pueden exportar funciones, objetos o valores para ser reutilizados en otras partes de una aplicación. Esta organización permite mantener el código más limpio, modular y fácil de mantener. Node.js incluye varios módulos integrados, como fs para trabajar con archivos o http para crear servidores, y también permite crear módulos personalizados.
Al trabajar con módulos en Node.js, se recomienda dividir el código en partes pequeñas y reutilizables, usar nombres claros para los archivos y evitar dependencias circulares. Para módulos propios, es buena idea exportar solo lo necesario y no toda la funcionalidad interna, manteniendo un encapsulamiento limpio. Además, cuando se trabaja con ESM, es conveniente mantener la coherencia de import/export en todo el proyecto.
CommonJS (require y module.exports)
El sistema de módulos original de Node.js se llama CommonJS. Para importar un módulo se utiliza require(), y para exportar valores o funciones desde un módulo se usa module.exports.
Ejemplo de módulo personalizado (math.js):
// math.js
function sumar(a, b) {
return a + b;
}
function restar(a, b) {
return a - b;
}
module.exports = { sumar, restar };
Ejemplo de uso en otro archivo (app.js):
const math = require('./math');
console.log(math.sumar(5, 3)); // 8
console.log(math.restar(5, 3)); // 2
ES Modules (import y export)
A partir de ES6, Node.js soporta ES Modules (ESM), que utilizan la sintaxis import y export. Esto permite una forma más clara y estandarizada de organizar el código, compatible con navegadores modernos y frameworks actuales. Para usar ESM en Node.js, podemos cambiar la extensión de los archivos a .mjs o indicar "type": "module" en el package.json del proyecto.
Exportaciones nombradas
Las exportaciones nombradas permiten exportar varias funciones, objetos o clases desde un mismo archivo. Cada exportación debe ser importada utilizando el mismo nombre que se definió al exportarla.
Ejemplo: exportar varias funciones
// math.mjs
export function sumar(a, b) {
return a + b;
}
export function restar(a, b) {
return a - b;
}
export function multiplicar(a, b) {
return a * b;
}
Importación de funciones nombradas
import { sumar, restar } from './math.mjs';
console.log(sumar(5, 3)); // 8
console.log(restar(5, 3)); // 2
También se pueden importar todas las exportaciones de un módulo usando un alias:
import * as math from './math.mjs';
console.log(math.multiplicar(4, 3)); // 12
Exportación por defecto (default)
Un módulo puede tener una exportación por defecto, que se importa sin necesidad de usar llaves {}. Esto es útil cuando el módulo exporta una función principal, un objeto o una clase.
Ejemplo: exportación de función por defecto
// saludo.mjs
export default function saludar(nombre) {
return `Hola, ${nombre}!`;
}
Importación de exportación por defecto
import saludar from './saludo.mjs';
console.log(saludar("Ana")); // Hola, Ana!
Exportar una clase
Se pueden exportar clases de la misma manera que funciones, ya sea de forma nombrada o por defecto:
Exportación nombrada de clase
// persona.mjs
export class Persona {
constructor(nombre, edad) {
this.nombre = nombre;
this.edad = edad;
}
saludar() {
return `Hola, soy ${this.nombre}`;
}
}
Importación de clase
import { Persona } from './persona.mjs';
const p = new Persona("Carlos", 30);
console.log(p.saludar()); // Hola, soy Carlos
Exportación por defecto de clase
// animal.mjs
export default class Animal {
constructor(especie) {
this.especie = especie;
}
info() {
return `Este es un ${this.especie}`;
}
}
import Animal from './animal.mjs';
const a = new Animal("gato");
console.log(a.info()); // Este es un gato
Exportar un objeto con múltiples funciones
Otra forma habitual es exportar un objeto que agrupe varias funciones, lo que permite importar todo de forma unificada:
// calculadora.mjs
function sumar(a, b) { return a + b; }
function restar(a, b) { return a - b; }
export default {
sumar,
restar
};
import calculadora from './calculadora.mjs';
console.log(calculadora.sumar(3, 4)); // 7
console.log(calculadora.restar(10, 6)); // 4
Buenas prácticas con ES Modules
Se recomienda mantener coherencia en todo el proyecto, usando ya sea exportaciones nombradas o por defecto, pero evitando mezclarlas innecesariamente. Para módulos que exportan varias funciones, objetos o clases, las exportaciones nombradas suelen ser más claras, mientras que las exportaciones por defecto son útiles para un elemento principal del módulo. Mantener un estilo consistente ayuda a la legibilidad y al mantenimiento del código.