← JavaScript: el lenguaje

Sesión 13 · Semana 5

Módulos ES

Hoy · Hoja de ruta

  1. 1. Aprende: Cómo se reparte el código en ficheros con import y export.
  2. 2. Haz: Separa datos, lógica y programa principal en tres módulos.
  3. 3. Comprueba: Todo funciona servido por un servidor local, y sabes por qué hace falta.

Antes de empezar · 5 minutos, sin apuntes

  1. ¿Cuántas líneas tiene ya tu fichero principal?
  2. Si otro proyecto quisiera tus funciones de catálogo, ¿qué le pasarías?
  3. ¿Qué partes de tu código son «datos», cuáles «reglas» y cuáles «uso»?

Exportar e importar

// js/datos.js
export const catalogo = [ /* ... */ ];
export const IVA = 0.21;
// js/catalogo.js
import { catalogo, IVA } from "./datos.js";

export function disponibles(productos = catalogo) {
  return productos.filter((p) => p.stock > 0);
}

export function valorAlmacen(productos = catalogo) {
  return productos.reduce((suma, p) => suma + p.precio * p.stock, 0);
}
// js/main.js
import { disponibles, valorAlmacen } from "./catalogo.js";

console.table(disponibles());
console.log(valorAlmacen().toFixed(2));

En el documento se declara un único enlace, con su tipo:

<script type="module" src="js/main.js"></script>

Con type="module" no hace falta defer: los módulos ya se ejecutan al final. Solo se enlaza el principal: los demás llegan por sus import.

Dos detalles que hacen perder una tarde

La extensión se escribe, y hace falta un servidor

En el navegador, la ruta del import lleva su .js: "./catalogo.js", no "./catalogo". Además debe comenzar por ./ o por /.

Además, los módulos no funcionan abriendo el fichero con doble clic. Verás un error de CORS con el esquema file://. Hay que servir la carpeta: la extensión Live Server de VS Code, o el servidor que montarás tú mismo en la UD5.

Exportación por defecto

export default function formatearPrecio(valor) {
  return `${valor.toFixed(2)}`;
}
import formatearPrecio from "./formato.js";

Un módulo puede tener una exportación por defecto y muchas con nombre. En este módulo preferimos las nombradas: el nombre viaja con la función y no se puede renombrar sin querer.

Qué va en cada fichero

El reparto de responsabilidades
  1. datos.js · qué hay
  2. catalogo.js · qué se puede preguntar
  3. main.js · qué hacemos hoy con ello

Es el mismo criterio de siempre: cada fichero responde a una pregunta. El criterio anticipa la separación en capas que verás en la UD6 y en el módulo de servidor.

Tarea 13 · Tres módulos

  1. Separa tu código en datos.js, catalogo.js y main.js.
  2. Exporta solo lo que se use fuera; el resto, privado del módulo.
  3. Añade formato.js con las funciones de presentación de texto.
  4. Enlaza únicamente main.js con type="module".
  5. Sirve la carpeta con un servidor local y comprueba que funciona.
  6. Provoca a propósito un import con la extensión olvidada y lee el error.
Objetivo mínimoTres módulos, un solo enlace, y todo funcionando bajo un servidor local.
Si lo tienesAñade un cuarto módulo de validación y úsalo desde catalogo.js.
RetoDibuja el grafo de dependencias de tu proyecto y comprueba que no hay ciclos.

Checkpoint · fin de la sesión 13

  • Tu código está repartido en módulos con una responsabilidad cada uno.
  • Solo enlazas el módulo principal, con type="module".
  • Escribes la extensión en las rutas de importación.
  • Sabes por qué los módulos necesitan un servidor.

Antes de cerrar · 2 minutos, sin mirar

  1. ¿Qué error verás si abres el fichero con doble clic?
  2. ¿Cuántos módulos enlazas en el documento?
  3. ¿Qué diferencia hay entre exportación nombrada y por defecto?
Ver respuestas

1 · Un error de CORS por el esquema file://: los módulos exigen que la página se sirva por HTTP.

2 · Uno: el principal. Los demás entran por sus importaciones.

3 · La nombrada se importa entre llaves y con su nombre exacto; la de defecto se importa con el nombre que quieras.