Tipos de módulos ESM

Módulos ESM: HTML/CSS/JSON/WASM Modules


Anteriormente hemos hablado de módulos ESM con contenido Javascript, que son los que se han utilizado siempre hasta ahora. Sin embargo, sería genial poder hacer lo mismo con otro tipo de ficheros, como archivos .json, estilos .css o incluso archivos .html.

Justo esa es la idea de los Módulos ESM. No sólo vamos a tener Javascript Modules, sino que también podremos utilizar JSON Modules, CSS Modules o HTML Modules.

Sintaxis ampliada

Para importar módulos diferentes a Javascript, simplemente tenemos que utilizar la sintaxis ampliada, usando with e indicando el tipo de fichero mediante type. Por ejemplo, observa la siguiente línea de código:

import songs from "./songs.json" with { type: "json" };

Esta sería la forma de importar, de forma estática un fichero JSON desde Javascript. Ten en cuenta que se amplia el import con un with donde se indica un objeto de opciones con el tipo de dato importado en la propiedad type, que en nuestro ejemplo es un fichero .json.

De la misma forma, también podríamos hacerlo con un import dinámico:

const songs = await import("songs.json", { with: { type: "json" } });

Puede parecer extraño tener que escribir dos veces el formato a importar. Esto ocurre porque la extensión de un fichero no garantiza que se trate de ese fichero. Por esta razón, y por temas de seguridad, el desarrollador debe indicar el formato que se espera, de modo que se securice adecuadamente.

Tipos de módulos disponibles

Como hemos mencionado, si no incluimos la sintaxis ampliada, por defecto Javascript importa Modulos Javascript, sin embargo, mediante esta sintaxis ampliada podemos utilizar otros módulos:

Tipos de módulosDescripción
JS modulesEl tipo de módulo por defecto. Soportado desde Chrome 61+.
JSON modulesMódulos para ficheros .json. Soportado desde Chrome 91+.
CSS modulesMódulos para ficheros .css. Soportado desde Chrome 93+.
HTML modulesMódulos para ficheros .html. Aún no soportado en Chrome.
WASM modulesMódulos para ficheros .wasm. Aún no soportado en Chrome.

Si utilizamos el type: "json", podemos importar archivos JSON directamente en nuestro código. Como vimos antes, la sintaxis sería la siguiente:

import songs from "./songs.json" with { type: "json" };

// [
//  { name: "No quiero cambiar", author: "ManzDev" },
//  { name: "Resolví el problema", author: "ManzDev" }
// ]

Entonces, en songs obtendremos un objeto o un array con el contenido del fichero .json indicado. No necesitaremos parsearlo con JSON.parse() ni nada similar, directamente será posible trabajar con él.

Es posible que tengas la impresión de haber importado archivos .json en Javascript sin necesidad de esta sintaxis. En frameworks de Javascript se usan automatizadores con Node que los pueden cargar de forma transparente al desarrollador.

Si utilizamos el type: "css", podemos importar archivos CSS directamente en nuestro código, obteniendo un objeto CSSStyleSheet (y no una cadena de texto con el contenido CSS). Este objeto es una forma nativa de trabajar con una hoja de estilos:

import styles from "./styles.css" with { type: "css" };

// CSSStyleSheet {
//   cssRules: [
//      { selectorText: ".container", cssText: "...", style: { ... }, ... }
//      { selectorText: ".item", cssText: "...", style: { ... }, ... }
//   ],
//   disabled: false,
//   type: "text/css",
//   ...
// }

En este caso, observa que tenemos un objeto con toda la información de la hoja de estilos: las reglas que contiene, los selectores, las propiedades de cada bloque, etc... Con esto, podemos manipular los estilos como lo hacemos con el DOM de HTML, pero respecto a CSS.

Si quieres ver algo más sobre esto, echa un vistazo al post sobre CSS en WebComponents.

¡OJO! Esta funcionalidad aún no está soportada y es sólo una propuesta.

La idea de los HTML Modules es que si utilizamos type: "html" podamos importar elementos HTML y traernoslos a un objeto Javascript del DOM. Algo que se podría utilizar como una suerte de motor de plantillas nativo directamente utilizable en Javascript:

import { container } from "./user.html" with { type: "html" };

// <div class="container">
//   <div class="user">
//     ...
//   </div>
// </div>

Luego de importarlo, bastaría con un document.body.append(container) para añadir el elemento HTML en el <body>.

¡OJO! Esta funcionalidad aún no está soportada y es sólo una propuesta.

De la misma forma que los anteriores, WASM Modules podría permitir la importación de módulos WebAssembly mediante type: "wasm". Sin embargo, de momento es sólo una característica que quizás sea posible en el futuro.

Hay que tener especial cuidado con el nombre CSS Modules, ya que existe una estrategia no estándar que se utilizó (y aún se utiliza) durante muchos años para modularizar los ficheros CSS en pequeños módulos. Sin embargo, los módulos CSS de los que hablamos en este post no tienen nada que ver con esos.

También es posible que nos encontremos con una característica llamada Imports assertions. Durante un breve espacio de tiempo, la característica with se escribía como assert. Sin embargo, se decidió renombrarla y with es la sintaxis definitiva.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev