Imagina que tienes un proyecto con miles de líneas de código en un solo archivo. Encontrar algo, entender qué hace cada parte, o no romper algo cuando tocas otra cosa... sería una pesadilla. 🫠
Los módulos son la solución: te permiten dividir tu código en archivos separados, donde cada archivo tiene una responsabilidad clara y puede compartir funcionalidad con los demás.
En los inicios de JavaScript, todo el código se cargaba con etiquetas <script> en el HTML y compartía un mismo espacio global:
<!-- Todo está en el scope global 😰 -->
<script src="utils.js"></script>
<script src="api.js"></script>
<script src="app.js"></script>
// utils.js
var nombre = 'Utilidades'
function formatear(texto) {
return texto.toUpperCase()
}
// api.js
var nombre = 'API' // 💥 ¡Sobreescribe la variable de utils.js!
function obtenerDatos() {
// ...
}
// app.js
console.log(nombre) // 'API' — no 'Utilidades'
Al compartir el scope global, cualquier variable o función de un archivo podía ser sobreescrita accidentalmente por otro archivo. Esto causaba errores muy difíciles de detectar.
<script>, las cosas dejan de funcionar.Antes de los módulos nativos, la comunidad inventó patrones para resolver estos problemas.
Una IIFE es una función que se ejecuta inmediatamente al definirse. Crea un scope propio y evita contaminar el scope global:
// utils.js
var MisUtils = (function() {
// Variables privadas (no accesibles desde fuera)
var version = '1.0'
// Solo exponemos lo que queremos
return {
formatear: function(texto) {
return texto.toUpperCase()
},
getVersion: function() {
return version
}
}
})()
// app.js
console.log(MisUtils.formatear('hola')) // 'HOLA'
console.log(MisUtils.getVersion()) // '1.0'
console.log(MisUtils.version) // undefined (¡es privada!)
Esto funcionaba, pero era verboso e incómodo. Cada librería creaba su variable global (jQuery, _, React, etc.) y seguías dependiendo del orden de los <script>.
Cuando nació Node.js en 2009, se creó CommonJS: el primer sistema real de módulos para JavaScript. Usa require para importar y module.exports para exportar:
// utils.js (CommonJS)
function formatear(texto) {
return texto.toUpperCase()
}
module.exports = { formatear }
// app.js (CommonJS)
const { formatear } = require('./utils')
console.log(formatear('hola')) // 'HOLA'
CommonJS funciona muy bien en Node.js, pero tiene un problema: es síncrono. Carga los archivos uno por uno, de arriba a abajo. Esto es perfecto para un servidor, pero no funciona en el navegador, donde cargar archivos es asíncrono.
Nota💡 Hoy en día, Node.js también soporta los módulos nativos de JavaScript (ES Modules), que veremos a continuación.
En 2015, con ES6 (ECMAScript 2015), JavaScript añadió su propio sistema de módulos al lenguaje: los ES Modules (ESM). Es el estándar que funciona tanto en navegadores como en Node.js.
Las principales ventajas de ES Modules son:
Para usar módulos en HTML, solo necesitas añadir type="module" al <script>:
<script type="module" src="app.js"></script>
Con type="module", el archivo app.js se comporta como un módulo:
import y export.defer).'use strict') automáticamente.En Node.js, tienes dos opciones para usar ES Modules:
Opción 1: Usa la extensión .mjs:
// utils.mjs
export function formatear(texto) {
return texto.toUpperCase()
}
Opción 2: Añade "type": "module" en tu package.json:
{
"name": "mi-proyecto",
"type": "module"
}
Con la Opción 2, todos los archivos .js del proyecto se tratan como módulos ES.
| Sistema | Año | Sintaxis | Dónde funciona |
|---|---|---|---|
| Scripts globales | 1995 | <script> | Navegador |
| IIFE | ~2000 | (function(){})() | Navegador |
| CommonJS | 2009 | require / module.exports | Node.js |
| ES Modules | 2015 | import / export | Navegador + Node.js |
Los ES Modules son el estándar actual y lo que deberías usar en tus proyectos. En las próximas lecciones veremos cómo usarlos en profundidad.
Inicia sesión
Para guardar tu progreso y desbloquear logros