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

时间:2015-07-11 07:19:47

标签: javascript node.js ecmascript-6 babeljs

在我正在合作的项目中,我们有两个选择,我们可以使用哪个模块系统:

  1. 使用require导入模块,并使用module.exportsexports.foo导出。
  2. 使用ES6 import导入模块,并使用ES6 export
  3. 导出

    使用其中一个是否有任何性能优势?如果我们使用ES6模块而不是节点模块,还有什么我们应该知道的吗?

10 个答案:

答案 0 :(得分:608)

  

使用其中一个是否有任何性能优势?

请记住,还没有本身支持ES6模块的JavaScript引擎。你说你自己在使用巴别塔。 Babel默认情况下会将importexport声明转换为CommonJS(require / module.exports)。因此,即使您使用ES6模块语法,如果您在Node中运行代码,也将使用CommonJS。

CommonJS和ES6模块之间存在技术差异,例如: CommonJS允许您动态加载模块。 ES6不允许这样做but there is an API in development for that

由于ES6模块是标准的一部分,我会使用它们。

答案 1 :(得分:146)

您可能需要考虑以下几种用法/功能:

需要:

  • 您可以在加载的模块名称不是的地方进行动态加载 预定义/静态,或仅在有条件地加载模块的情况下 它是“真正需要的”(取决于某些代码流)。
  • 正在加载 同步。这意味着如果你有多个require,那么它们就是。{ 一个接一个地加载和处理。

ES6进口:

  • 你可以使用 命名导入以选择性地仅加载您需要的部分。这样可以 节省记忆。
  • 导入可以是异步的(在当前的ES6模块加载器中,实际上也是如此)并且可以更好地执行。

此外,Require模块系统不是基于标准的。现在ES6模块存在的可能性很小。将来,在各种实现中将对ES6模块提供原生支持,这在性能方面将是有利的。

答案 2 :(得分:36)

主要优点是句法:

  • 更多声明/紧凑语法
  • ES6模块基本上会使UMD(通用模块定义)过时 - 基本上消除了CommonJS和AMD(服务器与浏览器)之间的分裂。

您不太可能看到ES6模块带来任何性能优势。即使在浏览器中完全支持ES6功能,您仍然需要一个额外的库来捆绑模块。

答案 3 :(得分:28)

  

使用其中一个是否有任何性能优势?

目前的答案是否定的,因为当前的浏览器引擎都没有从ES6标准中实现import/export

某些比较图表http://kangax.github.io/compat-table/es6/没有考虑到这一点,因此当您看到Chrome的几乎所有绿色时,请小心。来自ES6的import关键字未被考虑在内。

换句话说,包括V8在内的当前浏览器引擎无法通过任何JavaScript指令从主JavaScript文件导入新的JavaScript文件

(根据ES6规范,我们可能仍然只需要a few bugs away或几年,直到V8实现了这一点。)

document就是我们所需要的,而document就是我们必须遵守的。

ES6标准表示在我们读取模块之前模块依赖应该存在,就像在编程语言C中那样,我们有(头文件).h文件。

这是一个良好且经过良好测试的结构,我相信创建ES6标准的专家会考虑到这一点。

这使得Webpack或其他软件包捆绑软件能够在某些特殊情况下优化软件包,并减少软件包中不需要的某些依赖项。但是,如果我们有完美的依赖关系,这将永远不会发生。

import/export本机支持生效之前需要一些时间,并且require关键字不会长时间在任何地方。

什么是require

这是加载模块的node.js方式。 (https://github.com/nodejs/node

Node使用系统级方法来读取文件。使用require时,您基本上依赖于此。 require将在某些系统调用中结束,例如uv_fs_open(取决于最终系统,Linux,Mac,Windows)以加载JavaScript文件/模块。

要检查是否属实,请尝试使用Babel.js,您会看到import关键字将转换为require

enter image description here

答案 4 :(得分:27)

使用ES6模块可以用于树摇动&#39 ;;即启用Webpack 2,Rollup(或其他捆绑包)来识别未使用/导入的代码路径,因此不能将其放入生成的捆绑包中。这可以通过消除您永远不需要的代码来显着减少其文件大小,但默认情况下捆绑了CommonJS,因为Webpack等人无法知道是否需要它。

这是使用代码路径的静态分析完成的。

例如,使用:

import { somePart } 'of/a/package';

...给捆绑商一个提示,package.anotherPart不是必需的(如果它没有被导入,它就不会被使用 - 对吗?),所以它赢了&# 39;打扰捆绑它。

要为Webpack 2启用此功能,您需要确保您的转换器不会吐出CommonJS模块。如果您正在使用带有babel的es2015插件,则可以在.babelrc中将其停用,如下所示:

{
  "presets": [
    ["es2015", { modules: false }],
  ]
}

Rollup和其他人可能会有不同的工作方式 - 如果您有兴趣,请查看文档。

答案 5 :(得分:25)

截至目前,ES6的导入,导出为always compiled to CommonJS,因此使用一种或另一种没有好处。尽管建议使用ES6,因为当发布来自浏览器的本机支持时,它应该是有利的。原因是,您可以从一个文件导入部分文件,而使用CommonJS则需要所有文件。

ES6→PathFigure

CommonJS→import, export default, export

下面是这些的常用用法。

ES6导出默认值

require, module.exports, exports.foo

ES6导出多个并导入多个

// hello.js
function hello() {
  return 'hello'
}
export default hello

// app.js
import hello from './hello'
hello() // returns hello

CommonJS module.exports

// hello.js
function hello1() {
  return 'hello1'
}
function hello2() {
  return 'hello2'
}
export { hello1, hello2 }

// app.js
import { hello1, hello2 } from './hello'
hello1()  // returns hello1
hello2()  // returns hello2

CommonJS模块。导出多个

// hello.js
function hello() {
  return 'hello'
}
module.exports = hello

// app.js
const hello = require('./hello')
hello()   // returns hello

答案 6 :(得分:14)

当涉及异步或延迟加载时,import ()更强大。看看我们何时以异步方式需要该组件,然后我们使用importconst变量使用await以某种异步方式使用它。

const module = await import('./module.js');

或者,如果您想使用require(),那么

const converter = require('./converter');

事情import()实际上是异步的。正如ReactConf中的neehar venugopal所提到的,您可以使用它来动态加载客户端架构的反应组件。

在路由方面也更好。当用户将特定网站连接到其特定组件时,这是使网络日志下载必要部分的一个特殊事情。例如仪表板之前的登录页面不会下载仪表板的所有组件。因为需要当前即登录组件,只会下载。

同样适用于export:ES6 export与CommonJS module.exports完全相同。

注意 - 如果您正在开发node.js项目,那么您必须严格使用require(),因为如果您将节点异常错误设为invalid token 'import'将使用import。因此节点不支持导入语句。

更新 - 根据Dan Dascalescu的建议:自v8.5.0(2017年9月发布)以来,node --experimental-modules index.mjs允许您使用不含Babel的import。您可以(并且应该)publish your npm packages as native ESModule, with backwards compatibility使用旧的require方式。

有关使用异步导入的更多信息,请参阅此内容 - https://www.youtube.com/watch?v=bb6RCrDaxhw

答案 7 :(得分:5)

我个人使用import,因为我们可以使用import导入所需的方法,成员。

import {foo, bar} from "dep";

FileName: dep.js

export foo function(){};
export const bar = 22

归功于Paul Shan。 More info

答案 8 :(得分:3)

最重要的一点是,ES6模块确实是官方标准,而CommonJS(Node.js)模块不是。

在2019年,84%个浏览器支持ES6模块。尽管Node.js将它们放在--experimental-modules标志的后面,但还有一个方便的节点包称为esm,它使集成更流畅。

在这些模块系统之间可能会遇到的另一个问题是代码位置。 Node.js假定源代码保存在node_modules目录中,而大多数ES6模块则部署在平面目录结构中。这些都不容易调和,但是可以通过使用安装前和安装后脚本来入侵package.json文件来完成。这是一个示例isomorphic module和一个article解释其工作原理。

答案 9 :(得分:0)

不确定为什么会这样(可能是优化-延迟加载吗?),但我注意到如果不使用导入的模块,import可能无法解析代码。
在某些情况下,这可能不是预期的行为。

以讨厌的Foo类作为示例依赖项。

foo.ts

export default class Foo {}
console.log('Foo loaded');

例如:

index.ts

import Foo from './foo'
// prints nothing

index.ts

const Foo = require('./foo').default;
// prints "Foo loaded"

index.ts

(async () => {
    const FooPack = await import('./foo');
    // prints "Foo loaded"
})();

另一方面:

index.ts

import Foo from './foo'
typeof Foo; // any use case
// prints "Foo loaded"