Este artículo presentará ejemplos de módulos ECMAScript (ES)—que puede lograr con ellos y donde encontrara algunas limitaciones. Todos los navegadores lanzados después de mayo de 2018 admiten módulos ES, por lo que puede asumir que son seguros de usar en la mayoría de los casos.
Codificación sin módulos ES
Antes de que tuviéramos módulos Es, todo JS tenía que importarse globalmente. Cada archivo podría acceder a variables previamente definidas y dejar cosas para el código ejecutado mas tarde. El orden de las importaciones importaba, especialmente porque las cosas importadas mas tarde podrían anular los valores anteriores. Las importaciones de la vieja escuela en acción se veían así:
display-data.js
:
document.body.innerHTML = "lorem ipsum";
log.js
:
console.log("Some test info");
index.html
:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>No modules</title>
<link rel="shortcut icon" href="#" />
</head>
<body>
<script src="./display-data.js"></script>
<script src="./log.js"></script>
</body>
</html>
Problemas
Hay dos problemas principales con esta propuesta:
I. Contamina el ámbito global. Si tiene algunos archivos que definen el mismo valor, colisionaran y se anularan entre sí. Buena suerte para encontrar y corregir los errores que puede causar. Ejemplo:
data-1.js
:
var data = “lorem ipsum”;
data-2.js
:
var data = “sin dolor”;
index.html
:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Name collision</title>
<link rel="shortcut icon" href="#" />
</head>
<body>
<script src="./data-1.js"></script>
<script src="./data-2.js"></script>
<script>
document.body.innerHTML = data;
</script>
</body>
</html>
La solución alternativa mas común fue utilizar una expresión de función invocada inmediatamente. Esto aisló bloques de código y evitó la contaminación del alcance global, pero al mismo tiempo, hizo que el código fuera más confuso.
II. Cualquier dependencia tenia que gestionarse y resolverse manualmente. Si tenía un archivo que dependía de otro, entonces tenía que asegurarse de importar esos archivos en el orden correcto. Por ejemplo:
log-data.js
:
console.log(data);
data.js
:
const data = ‘some data’;
display-data.js
:
document.html = data;
index.html
:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>File order</title>
<link rel="shortcut icon" href="#" />
</head>
<body>
<script src="./log-data.js"></script>
<script src="./data.js"></script>
<script src="./display-data.js"></script>
</body>
</html>
Como puedes ver aquí, la parte “display data” (mostrar datos) funciona como se esperaba, mientras que el “logging data” (registro de datos) falla.
Módulos ES en acción
¿Cuál es la diferencia si hacemos lo mismo con los módulos ES? En primer lugar, define las dependencias a nivel de código. Entonces, si en un archivo desea valores de otro, simplemente especifíquelo en el mismo archivo. Este enfoque marca la diferencia, especialmente en la lectura de código: solo necesita abrir un archivo para tener una idea de todo el contexto que está usando con solo leerlo.
Entonces, ¿Cómo usamos los módulos ES?
data.js
:
export const data = "lorem ipsum";
display-data.js
:
import { data } from "./data.js";
document.body.innerHTML = data;
index.html
:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Simple modules</title>
<link rel="shortcut icon" href="#" />
</head>
<body>
<script type="module" src="./display-data.js"></script>
</body>
</html>
Los principales cambios en este código:
- Agregando
type=”module”
a<script>
importa en el archivo HTML. - Utilizando palabras clave de exportación e importación en los archivos JS para definir y cargar módulos.
Varios archivos que importan el mismo archivo
Podemos hacer que nuestro ejemplo sea más interesante importando los mismos archivos dos veces. Debido a que necesitamos que cada archivo sea independiente del otro, la importación se agregará dos veces—en cada archivo por separado. Los navegadores gestionan la importación correctamente y cargan el archivo solo una vez.
data.js
:
export const data = "lorem ipsum";
display-data.js
:
import { data } from "./data.js";
document.body.innerHTML = data;
log-data.js
:
import { data } from "./data.js";
console.log(data);
index.html
:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Shared import</title>
<link rel="shortcut icon" href="#" />
</head>
<body>
<script type="module" src="./display-data.js"></script>
<script type="module" src="./log-data.js"></script>
</body>
</html>
Carga diferida
La carga diferida retrasa la parte de carga de la aplicación hasta que el código es necesario. Esta es una técnica de optimización más complicada que cargar todo a la vez, pero permite un mayor control sobre qué se carga y cuándo. En el siguiente ejemplo, cargo y visualizo datos después de un retraso de medio segundo:
display-data.js
:
setTimeout(
() =>
import("./data.js").then(({ data }) => {
document.body.innerHTML = data;
}),
500
);
data.js
:
export const data = "lorem ipsum";
index.html
:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Lazy load</title>
<link rel="shortcut icon" href="#" />
</head>
<body>
<script type="module" src="./display-data.js"></script>
</body>
</html>
¿El módulo ES cubre todo lo que necesitamos en JS moderno?
Aunque los módulos nativos de ES mejoran significativamente los modelos anteriores de inclusión de cosas, carecen de algunas características esenciales para el desarrollo moderno de JavaScript. En este momento, no puede hacer lo siguiente:
- Importar tipos distintos a JS. Algunos otros archivos están en proceso JSON, pero pasará mucho tiempo antes de que lo tengamos en el navegador.
- Importe bibliotecas de terceros al estilo de Node.js. Podrías copiar archivos durante la construcción e importarlos desde una ubicación dentro de
node_modules
, pero se siente mucho más complicado que simplementeimportar la "biblioteca"
. - No hay transpilación. Gran parte del JS moderno está escrito en otros lenguajes, por ejemplo, TypeScript. Incluso JS puro necesita transpilación para admitir navegadores más antiguos o utilizar las funciones de lenguaje más recientes.
Por estas razones, en la mayoría de los proyectos, verá paquetes JS, una especie de compilador que prepara la compilación para las implementaciones. Si está interesado en los paquetes, hágamelo saber en los comentarios y consulte los enlaces.
Enlaces
- repositorio de ejemplos
- todos los ejemplos
- mi curso de video para esbuild
- mi curso de video para paquete web
Resumen
En esta publicación, analizamos casos de uso críticos de módulos ES. El siguiente paso sería configurar algún paquete JS para repasar las limitaciones de los módulos nativos.