在node.js中,ES6变量导入名称?

时间:2021-08-11 15:40:25

is it possible to import something into module providing variable name while using ES6 import?

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

I.e. I want to import some module at a runtime depending on values provided in a config:

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

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

7 个解决方案

#1


47  

Not with the import statement. import and export are defined in such a way that they are statically analyzable, so they cannot depend on runtime information.

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

You are looking for the loader API (polyfill), but I'm a bit unclear about the status of the specification:

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

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

#2


22  

In addition to Felix's answer, I'll note explicitly that this is not currently allowed by the ECMAScript 6 grammar:

除了Felix的答案,我还会明确地指出,ECMAScript 6语法目前还不允许使用它:

ImportDeclaration :

ImportDeclaration:

  • import ImportClause FromClause ;

    进口ImportClause FromClause;

  • import ModuleSpecifier ;

    进口ModuleSpecifier;

FromClause :

FromClause:

  • from ModuleSpecifier
  • 从ModuleSpecifier

ModuleSpecifier :

ModuleSpecifier:

  • StringLiteral
  • StringLiteral

A ModuleSpecifier can only be a StringLiteral, not any other kind of expression like an AdditiveExpression.

一个调制器只能是一个StringLiteral,而不是任何其他类型的表达式,比如一个AdditiveExpression。

#3


15  

Whilst this is not actually a dynamic import (eg in my circumstance, all the files I'm importing below will be imported and bundled by webpack, not selected at runtime), a pattern I've been using which may assist in some circumstances is:

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

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

const templates = {
  Template1,
  Template2
};

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

or alternatively:

或者:

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

I don't think I can fall back to a default as easily with require(), which throws an error if I try to import a constructed template path that doesn't exist.

我认为我不能像使用require()那样轻易地回到默认值,如果我试图导入一个不存在的构造模板路径,这会抛出一个错误。

Good examples and comparisons between require and import can be found here: http://www.2ality.com/2014/09/es6-modules-final.html

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

Excellent documentation on re-exporting from @iainastacio: http://exploringjs.com/es6/ch_modules.html#sec_all-exporting-styles

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

I'm interested to hear feedback on this approach :)

我有兴趣听到关于这个方法的反馈:)

#4


5  

There is a new specification which is called a dynamic import for ES modules. Basically, you just call import('./path/file.js') and your good to go. The function returns a promise, which resolves with the module if the import was successful.

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

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

Major use cases include route based module importing for Polymer 3.0, React and Vue, which reduces download bandwidth because the bundles for the routes are only loaded when they're required.

主要的用例包括面向聚合3.0、React和Vue的基于路由的模块导入,这减少了下载带宽,因为路由的包只有在需要时才被加载。

Here's the proposed spec on Github.

这是Github上提出的规范。

Right now (January 2017) this feature is working in Chrome 62. The other major browsers are probably picking up this feature and implementing it down the line when ESmodule support is fully supported.

目前(2017年1月)Chrome 62正在使用这个功能。其他主要的浏览器可能会在ESmodule支持得到完全支持的情况下选择这个特性并将其实现。

Edit:
I should add that the spec requires imports to be statically analyzable, both the regular import as well as the dynamic import, which means that you can't use a variable name to declare your import path. So there is no solution to your question because the ES spec prevents this by design.

编辑:我应该补充说明,规范要求导入可以静态分析,包括常规导入和动态导入,这意味着您不能使用变量名来声明导入路径。所以你的问题没有解决方案,因为ES规范在设计上阻止了这一点。

#5


4  

I less like this syntax, but it work:
instead of writing

我不太喜欢这种语法,但它起作用了:而不是写作

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

use this syntax:

使用这种语法:

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

#6


3  

you can use the non-ES6 notation to do that. this is what worked for me:

你可以用非es6表示法。这就是对我起作用的地方:

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

#7


0  

I would do it like this

我应该这样做

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

#1


47  

Not with the import statement. import and export are defined in such a way that they are statically analyzable, so they cannot depend on runtime information.

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

You are looking for the loader API (polyfill), but I'm a bit unclear about the status of the specification:

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

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

#2


22  

In addition to Felix's answer, I'll note explicitly that this is not currently allowed by the ECMAScript 6 grammar:

除了Felix的答案,我还会明确地指出,ECMAScript 6语法目前还不允许使用它:

ImportDeclaration :

ImportDeclaration:

  • import ImportClause FromClause ;

    进口ImportClause FromClause;

  • import ModuleSpecifier ;

    进口ModuleSpecifier;

FromClause :

FromClause:

  • from ModuleSpecifier
  • 从ModuleSpecifier

ModuleSpecifier :

ModuleSpecifier:

  • StringLiteral
  • StringLiteral

A ModuleSpecifier can only be a StringLiteral, not any other kind of expression like an AdditiveExpression.

一个调制器只能是一个StringLiteral,而不是任何其他类型的表达式,比如一个AdditiveExpression。

#3


15  

Whilst this is not actually a dynamic import (eg in my circumstance, all the files I'm importing below will be imported and bundled by webpack, not selected at runtime), a pattern I've been using which may assist in some circumstances is:

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

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

const templates = {
  Template1,
  Template2
};

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

or alternatively:

或者:

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

I don't think I can fall back to a default as easily with require(), which throws an error if I try to import a constructed template path that doesn't exist.

我认为我不能像使用require()那样轻易地回到默认值,如果我试图导入一个不存在的构造模板路径,这会抛出一个错误。

Good examples and comparisons between require and import can be found here: http://www.2ality.com/2014/09/es6-modules-final.html

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

Excellent documentation on re-exporting from @iainastacio: http://exploringjs.com/es6/ch_modules.html#sec_all-exporting-styles

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

I'm interested to hear feedback on this approach :)

我有兴趣听到关于这个方法的反馈:)

#4


5  

There is a new specification which is called a dynamic import for ES modules. Basically, you just call import('./path/file.js') and your good to go. The function returns a promise, which resolves with the module if the import was successful.

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

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

Major use cases include route based module importing for Polymer 3.0, React and Vue, which reduces download bandwidth because the bundles for the routes are only loaded when they're required.

主要的用例包括面向聚合3.0、React和Vue的基于路由的模块导入,这减少了下载带宽,因为路由的包只有在需要时才被加载。

Here's the proposed spec on Github.

这是Github上提出的规范。

Right now (January 2017) this feature is working in Chrome 62. The other major browsers are probably picking up this feature and implementing it down the line when ESmodule support is fully supported.

目前(2017年1月)Chrome 62正在使用这个功能。其他主要的浏览器可能会在ESmodule支持得到完全支持的情况下选择这个特性并将其实现。

Edit:
I should add that the spec requires imports to be statically analyzable, both the regular import as well as the dynamic import, which means that you can't use a variable name to declare your import path. So there is no solution to your question because the ES spec prevents this by design.

编辑:我应该补充说明,规范要求导入可以静态分析,包括常规导入和动态导入,这意味着您不能使用变量名来声明导入路径。所以你的问题没有解决方案,因为ES规范在设计上阻止了这一点。

#5


4  

I less like this syntax, but it work:
instead of writing

我不太喜欢这种语法,但它起作用了:而不是写作

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

use this syntax:

使用这种语法:

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

#6


3  

you can use the non-ES6 notation to do that. this is what worked for me:

你可以用非es6表示法。这就是对我起作用的地方:

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

#7


0  

I would do it like this

我应该这样做

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