如何执行“变量”ES6导入?

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

例如,我想在运行时根据配置中提供的值导入一些模块:

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

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

82730 次浏览

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

您正在寻找 装载机 API (填料),但我对规范的状态有点不清楚:

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

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

进口声明 < 强烈 > :

  • 进口条款

  • Import < em > 模块说明符;

来自条款 < strong > :

  • 来自 < em > 模块说明符

模块说明符 < strong > :

  • 字符串

模块说明符只能是 字符串,不能是其他类型的表达式,比如 加法表达式

虽然这实际上不是一个动态导入(例如,在我的情况下,下面我导入的所有文件都将被 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()可以很容易地回到默认值,如果我试图导入一个不存在的构造好的模板路径,它会抛出一个错误。

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

关于从@iainastacio 再出口的优秀文件: Http://exploringjs.com/es6/ch_modules.html#sec_all-exporting-styles

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

你可以使用非 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");

我会这么做

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

有一个新的规范,这是所谓的 动态输入为 ES 模块。 基本上,只要调用 import('./path/file.js')就可以了。该函数返回一个承诺,如果导入成功,该承诺将与模块一起解析。

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

用例

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

进一步资料

这是 Google 开发者的一个解释。

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

MDN统计,目前除 IE 之外的所有主流浏览器都支持 Caniuse.com,而且 Caniuse.com在全球市场份额中的支持率达到87% 。同样不支持 IE 或非铬边缘。

我理解在 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;

动态导入() (可在 Chrome63 + 中使用)将完成您的工作:

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();

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

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

在 github 中对同一问题的 回答对我来说非常有帮助。

可以使用 有活力的进口中的模板文字根据变量导入文件。

我使用动态导入将 .vue文件添加到 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 上使用了纱线 + vite + vue。