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

使用require导入模块,使用using module导出模块。Exports和Exports .foo。 使用ES6 import导入模块,使用ES6 export导出模块

使用其中一种是否有性能上的好处?如果我们要使用ES6模块而不是Node模块,还有什么我们应该知道的吗?


当前回答

主要优势是句法上的:

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

使用ES6模块你不太可能看到任何性能上的好处。你仍然需要一个额外的库来捆绑模块,即使在浏览器中完全支持ES6特性。

其他回答

主要优势是句法上的:

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

使用ES6模块你不太可能看到任何性能上的好处。你仍然需要一个额外的库来捆绑模块,即使在浏览器中完全支持ES6特性。

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

以讨厌的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"

到目前为止,ES6的导入和导出总是编译为CommonJS,所以使用其中一个没有好处。尽管推荐使用ES6,因为当浏览器发布本机支持时,它应该是有利的。原因是,你可以从一个文件中导入部分,而使用CommonJS,你必须需要整个文件。

ES6→导入,导出默认,导出

CommonJS→require, module。出口,exports.foo

下面是它们的常用用法。

ES6导出默认值

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

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

ES6导出多个和导入多个

// 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 module.exports

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

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

CommonJS模块。出口多

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

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

更新

自Node v12(2019年4月)以来,默认启用了对ES模块的支持,自Node v15(2020年10月)以来,它是稳定的(见这里)。包含节点模块的文件必须以.mjs或最近的包结尾。Json文件必须包含“type”:“module”。Node文档有更多的信息,还有关于CommonJS和ES模块之间的互操作。

在性能方面,新特性总是有可能没有现有特性优化得那么好。但是,由于模块文件只计算一次,所以性能方面可能会被忽略。最后,您必须运行基准测试以获得明确的答案。

ES模块可以通过import()函数动态加载。与require不同,this返回一个promise。


以前的回答

使用其中一种是否有性能上的好处?

请记住,目前还没有原生支持ES6模块的JavaScript引擎。你自己说过你在使用通天塔。无论如何,Babel默认将导入和导出声明转换为CommonJS (require/module.exports)。因此,即使你使用ES6模块语法,如果你在Node中运行代码,你将在底层使用CommonJS。

CommonJS和ES6模块之间有一些技术上的差异,例如CommonJS允许你动态加载模块。ES6不允许这样做,但有一个正在开发的API。

因为ES6模块是标准的一部分,所以我会使用它们。

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

2019年,84%的浏览器支持ES6模块。虽然node .js将它们放在——experimental-modules标志后面,但还有一个称为esm的方便的节点包,这使得集成更加顺利。

在这些模块系统之间可能遇到的另一个问题是代码位置。Node.js假定source保存在node_modules目录中,而大多数ES6模块部署在平面目录结构中。解决这些问题并不容易,但可以通过破解你的软件包来实现。带有前后安装脚本的Json文件。这里有一个同构模块的例子和一篇解释它如何工作的文章。