如何执行“变量”ES6导入

How to perform a “variable” ES6 import?

本文关键字:变量 ES6 导入 何执行 执行      更新时间:2023-09-26

在使用ES6导入时,是否可以将某些内容导入到提供变量名的模块中?

也就是说,我想在运行时根据配置中提供的值导入一些模块:

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

请注意,我使用的是Node.js,但答案必须考虑与ECMAScript模块的兼容性。

不使用import语句。importexport的定义方式是它们可以静态分析,因此它们不能依赖于运行时信息。

您正在寻找加载程序API(polyfill),但我有点不清楚规范的状态:

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

虽然这实际上不是一个动态导入(例如,在我的情况下,我在下面导入的所有文件都将由webpack导入和捆绑,而不是在运行时选择),但我一直在使用的一种模式在某些情况下可能会有所帮助:

import Template1 from './Template1.js';
import Template2 from './Template2.js';
const templates = {
  Template1,
  Template2
};
export function getTemplate (name) {
  return templates[name];
}

或者:

// 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;

我不认为require()可以很容易地恢复到默认值,如果我试图导入一个不存在的构建模板路径,它会引发错误。

在这里可以找到require和import之间的好例子和比较:http://www.2ality.com/2014/09/es6-modules-final.html

关于从@iainastacio重新导出的优秀文档:http://exploringjs.com/es6/ch_modules.html#sec_all-导出样式

我很想听听关于这种方法的反馈:)

有一个新的规范,称为ES模块的动态导入。基本上,你只要打电话给import('./path/file.js')就可以了。该函数返回一个promise,如果导入成功,该promise将与模块一起解析。

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

用例

用例包括React、Vue等基于路由的组件导入,以及在运行时需要延迟加载模块的能力。

进一步信息

以下是对谷歌开发者的解释。

浏览器兼容性(2020年4月)

根据MDN的数据,目前所有主要浏览器(IE除外)都支持它,caniuse.com在全球市场份额中显示出87%的支持率。同样,IE或非铬Edge不支持。

除了Felix的答案之外,我还要明确指出,ECMAScript 6语法目前不允许这样做:

进口申报

  • import ImportClause FromClause

  • import ModuleSpecifier

从条款

  • 来自 模块指定器

模块指定器

  • 字符串文字

ModuleSpecifier只能是StringLiteral,而不能是任何其他类型的表达式,如AdditiveExpression

我理解Node.js中专门针对ES6 import提出的问题,但以下内容可能会帮助其他人寻找更通用的解决方案:

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

请注意,如果您正在导入ES6模块并需要访问default导出,则需要使用以下其中一个:

let variableName = "es6.js";
// Assigning
const defaultMethod = require(`./utils/${variableName}`).default;
// Accessing
const something = require(`./utils/${variableName}`);
something.default();

您还可以将析构函数与此方法一起使用,这可能会增加对其他导入的语法熟悉程度:

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

不幸的是,如果您想访问default以及析构函数,则需要分多个步骤执行:

// 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;

我在使用Vue.js时遇到了类似的问题:当您在构建时在import(variableName)中使用变量时,Webpack不知道该在哪里查找。所以你必须将它限制在已知的路径上,并进行适当的扩展,比如:

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

github中对同一问题的回答对我很有帮助。

您可以使用非ES6表示法来实现这一点。这就是对我有效的:

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

我不太喜欢这种语法,但它有效:
而不是写入

import memberName from "path" + "fileName"; 
// this will not work!, since "path" + "fileName" need to be string literal

使用以下语法:

let memberName = require("path" + "fileName");

Dynamic import()(在Chrome 63+中可用)将完成您的工作。方法如下:

let variableName = 'test.js';
let utilsPath = './utils/' + variableName;
import(utilsPath).then((module) => { module.something(); });

/utils/test.js

export default () => {
  doSomething...
}

从文件调用

const variableName = 'test';
const package = require(`./utils/${variableName}`);
package.default();

我会像这个一样做

function load(filePath) {
     return () => System.import(`${filePath}.js`); 
     // Note: Change .js to your file extension
}
let A = load('./utils/' + variableName)
// Now you can use A in your module

这取决于情况。您可以在动态导入中使用模板文字来导入基于变量的文件。

我使用动态导入将.vue文件添加到vue路由器。我已排除Home.vue视图导入。

const pages = [
  'About',
  ['About', 'Team'],
]
const nodes = [
  {
    name: 'Home',
    path: '/',
    component: Home,
  }
]
for (const page of pages) {
  if (typeof page === 'string') {
    nodes.push({
      name: page,
      path: `/${page}`,
      component: import(`./views/${page}.vue`),
    })
  } else {
    nodes.push({
      name: _.last(page),
      path: `/${page.join('/')}`,
      component: import(`./views/${_.last(page)}.vue`)
    })
  }
}

这对我有效。我在replit上使用了yarn+vite+vue。