简体   繁体   English

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

[英]ES6 variable import name in node.js?

is it possible to import something into module providing variable name while using ES6 import?是否可以在使用 ES6 导入时将某些内容导入提供变量名的模块中?

Ie I want to import some module at a runtime depending on values provided in a config:即我想根据配置中提供的值在运行时导入一些模块:

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

Not with the import statement.不带import语句。 import and export are defined in such a way that they are statically analyzable, so they cannot depend on runtime information. importexport的定义方式使得它们可以静态分析,因此它们不能依赖于运行时信息。

You are looking for the loader API (polyfill) , but I'm a bit unclear about the status of the specification:您正在寻找loader API (polyfill) ,但我对规范的状态有点不清楚:

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

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可以在此处找到 require 和 import 之间的良好示例和比较: http ://www.2ality.com/2014/09/es6-modules-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 :)我很想听听关于这种方法的反馈:)

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 :进口声明

  • import ImportClause FromClause ;导入ImportClause FromClause ;

  • import ModuleSpecifier ;导入模块说明符;

FromClause :从句

  • from ModuleSpecifier来自模块说明符

ModuleSpecifier :模块说明符

  • StringLiteral字符串字面量

A ModuleSpecifier can only be a StringLiteral , not any other kind of expression like an AdditiveExpression . ModuleSpecifier只能是StringLiteral ,不能是AdditiveExpression等任何其他类型的表达式。

There is a new specification which is called a dynamic import for ES modules.有一个新规范称为 ES 模块的动态导入 Basically, you just call import('./path/file.js') and you're good to go.基本上,您只需调用import('./path/file.js')就可以了。 The function returns a promise, which resolves with the module if the import was successful.该函数返回一个promise,如果导入成功,该promise 将与模块一起解析。

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

Use cases用例

Use-cases include route based component importing for React, Vue etc and the ability to lazy load modules , once they are required during runtime.用例包括为 React、Vue 等导入基于路由的组件,以及在运行时需要时延迟加载模块的能力。

Further Information更多信息

Here's is an explanation on Google Developers .这是对Google Developers的解释。

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

According to MDN it is supported by every current major browser (except IE) and caniuse.com shows 87% support across the global market share.MDN称,当前所有主流浏览器(IE 除外)都支持它,而caniuse.com在全球市场份额中的支持率为 87%。 Again no support in IE or non-chromium Edge.同样不支持 IE 或非 Chromium Edge。

I understand the question specifically asked for ES6 import in Node.js, but the following might help others looking for a more generic solution:我了解在 Node.js 中专门针对 ES6 import提出的问题,但以下内容可能会帮助其他人寻找更通用的解决方案:

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

Note if you're importing an ES6 module and need to access the default export, you will need to use one of the following:请注意,如果您要导入 ES6 模块并需要访问default导出,则需要使用以下选项之一:

let variableName = "es6.js";

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

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

You can also use destructuring with this approach which may add more syntax familiarity with your other imports:您还可以通过这种方法使用解构,这可能会增加您对其他导入的语法熟悉:

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

Unfortunately, if you want to access default as well as destructuring, you will need to perform this in multiple steps:不幸的是,如果您想访问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;

you can use the non-ES6 notation to do that.你可以使用非 ES6 符号来做到这一点。 this is what worked for me:这对我有用:

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

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

Dynamic import() (available in Chrome 63+) will do your job. 动态 import() (在 Chrome 63+ 中可用)将完成您的工作。 Here's how:就是这样:

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

I had similar problem using Vue.js : When you use variable in import(variableName) at build time Webpack doesn't know where to looking for.我在使用Vue.js时遇到了类似的问题:当您在构建时在import(variableName)中使用变量时,Webpack 不知道在哪里寻找。 So you have to restrict it to known path with propriate extension like that:因此,您必须将其限制为具有适当扩展名的已知路径,如下所示:

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

That answer in github for the same issue was very helpful for me. github中针对同一问题的答案对非常有帮助。

./utils/test.js ./utils/test.js

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

call from file从文件调用

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

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

It depends.这取决于。 You can use template literals in dynamic imports to import a file based on a variable.您可以在动态导入中使用模板文字来基于变量导入文件。

I used dynamic imports to add .vue files to vue router.我使用动态导入将.vue文件添加到 vue 路由器。 I have excluded the Home.vue view import.我已经排除了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`)
    })
  }
}

This worked for me.这对我有用。 I was using yarn + vite + vue on replit.我在 repli 上使用了 yarn + vite + vue。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM