preloader

Importaciones dinámicas en JavaScript

Importaciones dinámicas en JavaScript

Las instrucciones de exportación e importación que discutimos en capítulos anteriores se denominan «estáticas». La sintaxis es bastante sencilla y estricta.

En primer lugar, no podemos generar dinámicamente ningún parámetro de import.

La ruta del módulo debe ser una cadena de texto literal, no puede ser una llamada a una función. Esto no funcionará:

				
					import ... from getModuleName(); // Error, from solo permite "string"

				
			

En segundo lugar, no podemos importar de manera condicional o en tiempo de ejecución:

				
					if(...) {
  import ...; // ¡Error, no permitido!
}

{
  import ...; // Error, no podemos poner importación en ningún bloque.
}

				
			

Esto se debe a que las instrucciones import/export proporcionan una base sólida para la estructura del código. Esto es beneficioso porque la estructura del código puede ser analizada, los módulos pueden ser ensamblados y agrupados en un archivo mediante herramientas especializadas, y las exportaciones no utilizadas pueden ser eliminadas («tree-shaken»). Esto es posible solo porque la estructura de las importaciones/exportaciones es simple y fija.

Pero, ¿cómo podemos importar un módulo de forma dinámica, según sea necesario?

La expresión import()

La expresión import(module) carga el módulo y devuelve una promesa que se resuelve en un objeto de módulo que contiene todas sus exportaciones. Se puede llamar desde cualquier lugar del código.

Podemos usarlo de manera dinámica en cualquier parte del código, por ejemplo:

				
					let modulePath = prompt("¿Qué módulo cargar?");

import(modulePath)
  .then(obj => <module object>)
  .catch(err => <loading error, e.g. if no such module>)

				
			

O, podríamos usar let module = await import(modulePath) si está dentro de una función asíncrona.

Por ejemplo, si tenemos el siguiente módulo say.js:

				
					// 📁 say.js
export function hi() {
  alert(`Hola`);
}

export function bye() {
  alert(`Adiós`);
}

				
			

…Entonces la importación dinámica podría ser así:

				
					let {hi, bye} = await import('./say.js');

hi();
bye();

				
			

O, si say.js tiene una exportación predeterminada:

				
					// 📁 say.js
export default function() {
  alert("¡Módulo cargado (exportación predeterminada)!");
}

				
			

…Luego, para acceder a él, podemos usar la propiedad default del objeto del módulo:

				
					let obj = await import('./say.js');
let say = obj.default;
// o, en una línea: let {default: say} = await import('./say.js');

say();

				
			

Aquí está el ejemplo completo:

				
					<!doctype html>
<script>
  async function load() {
    let say = await import('./say.js');
    say.hi(); // ¡Hola!
    say.bye(); // ¡Adiós!
    say.default(); // ¡Módulo cargado (exportación predeterminada)!
  }
</script>
<button onclick="load()">Haz clic aquí</button>

				
			

Notas importantes

  1. Las importaciones dinámicas funcionan en scripts normales, no requieren script type="module".

  2. Aunque import() parece una llamada a una función, es una sintaxis especial que solo usa paréntesis (similar a super()).

Por lo tanto, no podemos copiar import a una variable o usar call/apply con ella. No es una función.

Related Post

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *