Kodokon kodokon.com

Módulos ES: import/export, estructurar un proyecto

Estructura tus proyectos con módulos ES aprovechando su análisis estático y evitando los barrels tóxicos y las dependencias circulares.

8 min · 3 preguntas

Abrir esta lección en Kodokon

Los módulos ES son estáticos: las sentencias import y export se resuelven cuando se analiza el archivo, antes de que se ejecute cualquier código. Eso es lo que permite el tree-shaking (eliminar el código que nunca se importa) y detectar errores de nombres en tiempo de compilación. ¿Exportaciones nombradas o exportación por defecto? Las exportaciones nombradas ganan en casi todos los frentes: renombrado apto para la refactorización, autocompletado fiable y ninguna forma de importar la misma cosa bajo diez nombres distintos. Reserva la exportación por defecto para el caso en que el módulo exporta una cosa evidente.

JAVASCRIPT
export const TAX_RATE = 0.2;

export function applyTax(price) {
  return price * (1 + TAX_RATE);
}

export default class Cart {
  items = [];
  add(item) {
    this.items.push(item);
    return this;
  }
}
cart.js: exportaciones nombradas para las utilidades, por defecto para la clase central.

En el lado consumidor, cuatro formas: importación nombrada (con alias opcional mediante as), importación por defecto, importación de espacio de nombres (* as) e importación dinámica import(), que devuelve una promesa de un espacio de nombres. Esta última es el bloque de construcción del code splitting: cargar un módulo pesado (editor, gráfico, PDF) solo en el momento en que el usuario realmente lo necesita.

JAVASCRIPT
import Cart, { applyTax, TAX_RATE } from "./cart.js";
import * as cartModule from "./cart.js";

console.log(applyTax(100), TAX_RATE); // 120 0.2
console.log(cartModule.TAX_RATE); // 0.2

const lazy = await import("./cart.js");
const cart = new lazy.default();
console.log(cart instanceof Cart); // true
Formas estáticas e importación dinámica del mismo módulo.

Para la organización, prefiere dividir por funcionalidad (features/cart/, features/auth/) en lugar de por tipo técnico (controllers/, helpers/): el código que cambia junto vive junto, y eliminar una funcionalidad significa borrar una carpeta. Expón cada funcionalidad a través de un punto de entrada estrecho y trata cualquier importación que evite ese punto de entrada como una violación de límites.

Prueba de conocimientos

Comprueba que has retenido los puntos clave de esta lección.

  1. ¿Qué hace posible el tree-shaking con los módulos ES?
    • Los empaquetadores ejecutan el código para ver qué se usa
    • Las importaciones y exportaciones son estáticas y pueden analizarse sin ejecutar el código
    • Los módulos ES comprimen automáticamente el código muerto
  2. ¿Qué devuelve la expresión import("./module.js")?
    • El espacio de nombres del módulo, de forma síncrona
    • Una promesa resuelta con el espacio de nombres del módulo
    • Una función que carga el módulo cuando se la llama
    • Solo la exportación por defecto del módulo
  3. ¿Cuál es el principal riesgo de los barrel files (un índice que reexporta una carpeta entera)?
    • Hacen imposibles las exportaciones nombradas
    • Pueden cargar la carpeta entera por una sola importación y dificultar el tree-shaking
    • Impiden la importación dinámica de la carpeta