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

Posted

技术标签:

【中文标题】node.js中的ES6变量导入名称?【英文标题】:ES6 variable import name in node.js? 【发布时间】:2015-05-23 23:23:36 【问题描述】:

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

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

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

【问题讨论】:

@Bigood 是的,编译器抛出异常,Webstorm 也显示错误 【参考方案1】:

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

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

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

【讨论】:

我需要“要求”系统吗?它不在全球范围内.. P.s.我正在使用 babel js 它尚未在任何地方实现 AFAIK。您必须使用链接中的 polyfill。 刚刚检查过,它有点工作(尝试加载文件)但随后会弄乱其他模块的路径......太糟糕了,它本身不支持...... 这仍然是一个问题吗?我需要动态加载 ES6 模块,但我没有成功.. 虽然这是 2015 年的最佳答案,但 dynamic import() 在 ES2020 中已标准化,并受到 Node.js 和所有现代浏览器的支持,请参阅 this answer。【参考方案2】:

虽然这实际上不是动态导入(例如,在我的情况下,我在下面导入的所有文件都将由 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-exporting-styles

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

【讨论】:

点赞。我使用了“或替代”的方法。对我的自定义本地化解决方案很有帮助。 React docs: Choosing the Type at Runtime 我应该想到这一点。很好的解决方案,无论您如何导入东西(即使您没有导入任何东西)。有一个您以后想要获取名称或按名称获取的项目列表吗?将它们放在对象文字而不是数组文字中,并让对象语法根据它们的局部常量/变量名称来命名它们。如果您再次需要它们作为列表,只需执行Object.values(templates) 谢谢,这是一个简单地解决这个问题的好方法。非常感谢。【参考方案3】:

除了Felix's answer,我会明确指出ECMAScript 6 grammar目前不允许这样做:

进口声明

import ImportClause FromClause ;

导入 ModuleSpecifier ;

FromClause :

来自 ModuleSpecifier

ModuleSpecifier :

字符串字面量

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

【讨论】:

很遗憾,它没有扩展到包括conststring literals。它们是静态可分析的,不是吗?这将使重用依赖项的位置成为可能。 (例如,导入一个模板并让模板和模板的位置都可用)。【参考方案4】:

有一个新的规范,称为 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 等导入基于路由的组件,以及在运行时需要时延迟加载模块

更多信息

这是对Google Developers的解释。

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

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

【讨论】:

您确定您的编辑吗?该提案显示了一个带有可变路径的示例:github.com/tc39/proposal-dynamic-import#example @Blauhirn 我是,但您的链接清楚地表明这是一种可能性。虽然我不知道 webpack 如何解析这些导入 如果我错了,请纠正我,但 webpack 不会处理这些,是吗?我认为动态导入的关键在于它们在浏览器中“按原样”运行。 是的,您可以在浏览器中按原样运行它们。但是 webpack 会自动使用导入将您的应用程序拆分为多个包,用于应用程序的不同部分,例如路由。我一直在使用它们,它们真的很有帮助。就“处理”而言; webpack 会将导入传递给 babel,这将为旧版浏览器填充该功能。 明确一点:动态 import() 与变量一起工作,并且不需要进行静态分析(这就是“动态”的全部意义,当然吗?)。看我的回答。【参考方案5】:

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

【讨论】:

【参考方案6】:

您可以使用非 ES6 表示法来做到这一点。这对我有用:

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

【讨论】:

【参考方案7】:

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

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

使用这个语法:

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

【讨论】:

@UlysseBN 不一样?还是一种无关紧要的方式? @Jacob 他们真的完全不同,所以是的,这可能取决于你在做什么。第一种语法是静态评估的,而第二种语法是动态评估的。因此,例如,如果您使用的是 webpack,则无法正确地使用第二个执行 tree-shaking。还有很多其他差​​异,我建议您阅读文档,看看哪个更适合您! @Jacob - 没关系(在大多数情况下)。 require() 是 Node.JS 加载文件的方法,是早期版本。 import 语句是较新的版本,现在是官方语言语法的一部分。然而,在许多情况下,浏览器将使用前一个(在科学背后)。 require 语句还将兑现您的文件,因此如果第二次加载文件,它将从内存中加载(更好的性能)。导入方式有它自己的好处 - 如果您使用的是 WebPack。然后 webpack 可以删除死引用(这些脚本不会下载到客户端)。【参考方案8】:

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

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

【讨论】:

【参考方案9】:

我在使用Vue.js 时遇到了类似的问题:当您在构建时在import(variableName) 中使用变量时,Webpack 不知道在哪里寻找。因此,您必须将其限制为具有适当扩展名的已知路径:

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

That 在 github 上回答同样的问题对我很有帮助。

【讨论】:

【参考方案10】:

./utils/test.js

export default () => 
  doSomething...

从文件调用

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

【讨论】:

【参考方案11】:

我会这样做

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

【讨论】:

以上是关于node.js中的ES6变量导入名称?的主要内容,如果未能解决你的问题,请参考以下文章

Node.js 的 commonJS 规范 ES6 导入 js 文件

Node.js 的 commonJS 规范 ES6 导入 js 文件

如何在 Node.js 中使用 ES6 导入? [复制]

使用Node.js需要与ES6导入/导出

es6和node.js模块的区别

Node.js log4j-like 日志系统