¿Cómo realizar una importación ES6 “variable”?

7 minutos de lectura

Avatar de usuario de Vytautas Butkus
Vytautas Butkus

¿Es posible importar algo en un módulo proporcionando un nombre de variable mientras se usa la importación ES6?

Es decir, quiero importar algún módulo en tiempo de ejecución según los valores proporcionados en una configuración:

import something from './utils/' + variableName;

Tenga en cuenta que estoy usando Node.js, pero las respuestas deben tener en cuenta la compatibilidad con los módulos ECMAScript.

  • @Bigood sí, el compilador arroja y Webstorm también muestra un error

    –Vytautas Butkus

    20 de marzo de 2015 a las 14:10

no con el import declaración. import y export se definen de tal manera que son analizables estáticamente, por lo que no pueden depender de la información de tiempo de ejecución.

estas buscando el cargador API (polyfill)pero no tengo claro el estado de la especificación:

System.import('./utils/' + variableName).then(function(m) {
  console.log(m);
});

  • ¿Necesito “requerir” el sistema? No está en un ámbito global. PD: estoy usando babel js

    –Vytautas Butkus

    20 de marzo de 2015 a las 14:13


  • Todavía no está implementado en ningún lado AFAIK. Tienes que usar el polyfill del enlace.

    – Félix Kling

    20 de marzo de 2015 a las 14:13


  • Acabo de verificar, funciona un poco (intenta cargar el archivo) pero luego desordena las rutas para otros módulos… Lástima que no es compatible de forma nativa…

    –Vytautas Butkus

    20 de marzo de 2015 a las 14:26

  • ¿Sigue siendo un problema? Necesito cargar modulos ES6 dinamicamente pero no he tenido exito..

    – calbertts

    6 de febrero de 2016 a las 7:31

  • Si bien esta fue la mejor respuesta en 2015, dinámica import() se estandarizó en ES2020 y es compatible con Node.js y todos los navegadores modernos, consulte esta respuesta.

    –TJ Crowder

    9 de enero a las 11:08

avatar de usuario de ptim
optimo

Si bien esto no es realmente una importación dinámica (por ejemplo, en mi caso, todos los archivos que estoy importando a continuación serán importados y agrupados por webpack, no seleccionados en tiempo de ejecución), un patrón que he estado usando que puede ayudar en algunas circunstancias es :

import Template1 from './Template1.js';
import Template2 from './Template2.js';

const templates = {
  Template1,
  Template2
};

export function getTemplate (name) {
  return templates[name];
}

o alternativamente:

// index.js
export { default as Template1 } from './Template1';
export { default as Template2 } from './Template2';


// OtherComponent.js
import * as templates from './index.js'
...
// handy to be able to fall back to a default!
return templates[name] || templates.Template1;

No creo que pueda volver a un valor predeterminado tan fácilmente con require()que arroja un error si intento importar una ruta de plantilla construida que no existe.

Buenos ejemplos y comparaciones entre require e import se pueden encontrar aquí: http://www.2ality.com/2014/09/es6-modules-final.html

Excelente documentación sobre reexportación de @iainastacio:
http://exploringjs.com/es6/ch_modules.html#sec_all-exporting-styles

Me interesa escuchar comentarios sobre este enfoque 🙂

  • Votar a favor. Utilicé el enfoque “o alternativamente”. Funcionó de maravilla para mi solución de localización personalizada.

    – groundh0g

    24 de diciembre de 2018 a las 2:29

  • React docs: elegir el tipo en tiempo de ejecución

    – tim

    21 de enero de 2020 a las 8:57


  • Debería haber pensado en esto. Gran solución, no importa cómo esté importando cosas (e incluso si no está importando nada). ¿Tiene una lista de elementos de los que desea obtener el nombre o obtener por nombre más adelante? Póngalos en un literal de objeto en lugar de un literal de matriz, y deje que la sintaxis del objeto se encargue de nombrarlos en función de su nombre de constante/variable local. Si los necesita como una lista nuevamente, simplemente hágalo Object.values(templates).

    – Andrew Koster

    11 jun 2020 a las 22:40


  • Gracias, esta es una excelente manera de resolver este problema de manera simple. Muy apreciado.

    – DrCord

    20 de enero de 2021 a las 23:16

Avatar de usuario de Nicolai Schmid
Nicolás Schmid

Hay una nueva especificación que se llama importación dinámica para módulos ES. Básicamente, solo llamas import('./path/file.js') y estás listo para irte. La función devuelve una promesa, que resuelve con el módulo si la importación fue exitosa.

async function importModule() {
   try {
      const module = await import('./path/module.js');
   } catch (error) {
      console.error('import failed');
   }
}

casos de uso

Los casos de uso incluyen Importación de componentes basados ​​en rutas para React, Vue etc y la capacidad de módulos de carga lentauna vez que se requieren durante el tiempo de ejecución.

Más información

Aquí hay una explicación sobre Desarrolladores de Google.

Compatibilidad del navegador (abril de 2020)

De acuerdo a MDN es compatible con todos los principales navegadores actuales (excepto IE) y caniuse.com muestra un apoyo del 87 % en toda la cuota de mercado mundial. Nuevamente, no hay soporte en IE o Edge sin cromo.

  • ¿Estás seguro de tu edición? la propuesta muestra un ejemplo con una ruta variable: github.com/tc39/proposal-dynamic-import#example

    – phil294

    7 mayo 2018 a las 14:45

  • @Blauhirn Lo estaba, pero su enlace muestra claramente que es una posibilidad. Aunque no tengo idea de cómo webpack, por ejemplo, resolvería estas importaciones

    – Nicolai Schmid

    7 mayo 2018 a las 15:31

  • corrígeme si me equivoco, pero webpack no los procesa, ¿verdad? Pensé que el objetivo de las importaciones dinámicas era que se ejecutaran “tal cual” en el navegador.

    – phil294

    7 mayo 2018 a las 16:19

  • Sí, puede ejecutarlos en el navegador tal cual. Pero webpack usa automáticamente las importaciones para dividir su aplicación en múltiples paquetes para diferentes partes de su aplicación, por ejemplo, para rutas. Los uso todo el tiempo y son realmente útiles. Y en lo que respecta al “procesamiento”; webpack pasará las importaciones de babel, que polillenará la función para navegadores más antiguos.

    – Nicolai Schmid

    7 mayo 2018 a las 16:22


  • Para ser claros: importación dinámica () voluntad trabajar con variables y no se requiere que sea analizable estáticamente (¿ese es el punto central de ‘dinámico’, seguramente?). Mira mi respuesta.

    – Velojet

    25 de enero de 2019 a las 2:42

avatar de usuario de apsillers
apsilleres

Además de la respuesta de Felix, señalaré explícitamente que esto no está permitido actualmente por el Gramática ECMAScript 6:

Declaración de importación :

  • importar ImportarCláusulaDeCláusula ;

  • importar Especificador de módulo;

DeCláusula :

  • de Especificador de módulo

Especificador de módulo :

  • StringLiteral

A Especificador de módulo solo puede ser un StringLiteralno cualquier otro tipo de expresión como un Expresión aditiva.

Entiendo la pregunta formulada específicamente para ES6 import en Node.js, pero lo siguiente podría ayudar a otros que buscan una solución más genérica:

let variableName = "es5.js";
const something = require(`./utils/${variableName}`);

Tenga en cuenta si está importando un módulo ES6 y necesita acceder a la default exportar, necesitará usar uno de los siguientes:

let variableName = "es6.js";

// Assigning
const defaultMethod = require(`./utils/${variableName}`).default;

// Accessing
const something = require(`./utils/${variableName}`);
something.default();

También puede usar la desestructuración con este enfoque, lo que puede agregar más familiaridad con la sintaxis con sus otras importaciones:

// Destructuring 
const { someMethod } = require(`./utils/${variableName}`);    
someMethod();

Lamentablemente, si desea acceder default además de desestructurar, deberá realizar esto en varios pasos:

// ES6 Syntax
Import defaultMethod, { someMethod } from "const-path.js";

// Destructuring + default assignment
const something = require(`./utils/${variableName}`);

const defaultMethod = something.default;    
const { someMethod, someOtherMethod } = something;

avatar de usuario de mlevanon
mlevanon

puede usar la notación que no es ES6 para hacer eso. esto es lo que funcionó para mí:

let myModule = null;
if (needsToLoadModule) {
  myModule = require('my-module').default;
}

avatar de usuario de stanimirsp
stanimirsp

Tuve un problema similar al usar Vue.js: Cuando usa variable en import(variableName) en el momento de la compilación, Webpack no sabe dónde buscar. Por lo tanto, debe restringirlo a una ruta conocida con una extensión adecuada como esa:

let something = import("@/" + variableName + ".js") 

Que La respuesta en github para el mismo problema fue muy útil para mí.

¿Ha sido útil esta solución?