NodeJS计划支持导入/导出es6(es2015)模块


275

我一直在互联网上寻找有关此问题的明确答案。

当前,NodeJS仅使用CommonJS语法加载模块,如果您确实要使用标准的ES2015模块语法,则必须事先对其进行转换,或者在运行时使用外部模块加载器。

目前,我不太愿意使用这两种方法,NodeJS维护人员是否计划支持ES2015模块?我完全没有发现任何提示。

目前,NodeJS 6.x声称支持96%的ES2015功能,但没有任何模块参考(NodeJS ES2105支持链接)。

您是否知道在不久的将来NodeJS是否会立即支持这些模块?


2
谷歌搜索node es2015 modules,显示了以下结果的最上面的一个:github.com/nodejs/node/wiki/ES6-Module-Detection-in-Node
菲利克斯·克林

6
我个人将以“过于本地化”的方式投票结束这个问题,但是这种关闭的理由已经不存在了。假设Node明天将设法实现ES6模块。那您是否要删除问题,因为它不再相关了?还是至少要更新它?如果您已经知道某个问题将过时或需要“很快”更新,我认为这个问题不适合。但这只是我的意见,似乎还有其他人认为相反,这对我来说是可以的:)(一句话,这个问题当然很重要而且很有趣)
费利克斯·克林

2
我希望在Stack Universe中有一个这样的问题。从技术上讲,它可能不合适,但是我不知道我是否也确实是基于“观点”的。OP正在寻找针对特定问题的特定答案,但该答案(在某些时候)已经过时。
Wonko the Sane,

5
这个问题的替代措词:“ node.js对ES6模块的支持状态是什么?” 随着技术的发展,许多SO问题的答案会随着时间而改变。在登陆之前,我也很难找到答案。
乔·拉普

4
@FelixKling我想您想结束这个问题将是一个非常错误的决定,因为这是一个问题,到目前为止,已有211人发现该问题足以投票赞成。
穆罕默德·乌默尔(Um Muhammad Umer),

Answers:


302

节点13.2.0及以上

NodeJS 13.2.0现在支持不带标志的ES模块🎉但是,该实现仍被标记为实验性的,因此在生产中使用时应谨慎。

要在13.2.0中启用ESM支持,请将以下内容添加到您的package.json

{
  "type": "module"
}

所有.js.mjs(或不带扩展名的文件)将被视为ESM。

除了整个package.json选择加入之外,还有许多其他选项,有关详细信息,请参见13.2.0文档。

节点13.1.0及以下

那些仍在使用旧版本Node的用户可能想尝试esm模块加载器,这是NodeJS ES模块规范的生产就绪型实现:

node -r esm main.js

详细更新...

2019年4月23日

最近登陆的PR更改了检测ES模块的方式: https //github.com/nodejs/node/pull/26745

它仍然落后--experimental-modules,但是模块的加载方式发生了重大变化:

  • package.type可以是modulecommonjs
    • type: "commonjs"
      • .js 被解析为commonjs
      • 不带扩展名的入口点的默认值为commonjs
    • type: "module"
      • .js 被解析为esm
      • 默认不支持加载JSON或本机模块
      • 不带扩展名的入口点的默认值为esm
  • --type=[mode]让您在入口点上设置类型。将覆盖package.type入口点。
  • 新的文件扩展名.cjs
    • 这专门用于支持以该module方式导入commonjs 。
    • 这仅在esm加载器中,commonjs加载器保持不变,但是如果您使用完整的文件路径,则扩展名将在旧的加载器中工作。
  • --es-module-specifier-resolution=[type]
    • 选项是explicit(默认)和node
    • 默认情况下,我们的加载器不允许导入中的可选扩展名,如果存在一个扩展名,则模块路径必须包含扩展名
    • 默认情况下,我们的加载器不允许导入具有索引文件的目录
    • 开发人员可以使用--es-module-specifier-resolution=node启用commonjs说明符解析算法
    • 这不是“功能”,而是实验的一种实现。预期在删除标志之前会发生变化
  • --experimental-json-loader
    • 何时导入json的唯一方法 "type": "module"
    • 当启用时,所有内容import 'thing.json'都会独立于模式进行实验加载程序
    • 基于whatwg / html#4315
  • 您可以package.main用来设置模块的入口点
    • main中使用的文件扩展名将根据模块的类型进行解析

2019年1月17日

节点11.6.0仍在标志后面将ES模块列为实验模块。

2017年9月13日

NodeJS 8.5.0已发布,在标志后面支持mjs文件:

node --experimental-modules index.mjs

计划是删除v10.0 LTS版本的标志。

-过时的信息。出于历史目的保留在这里

2017年9月8日

NodeJS master分支已更新,最初支持ESM模块:
https //github.com/nodejs/node/commit/c8a389e19f172edbada83f59944cad7cc802d9d5

它应该在最新的每晚更新中可用(可以通过nvm进行安装以与现有安装一起运行):https : //nodejs.org/download/nightly/

并在--experimental-modules标志后面启用:

package.json

{
  "name": "testing-mjs",
  "version": "1.0.0",
  "description": "",
  "main": "index.mjs" <-- Set this to be an mjs file
}

然后运行:

node --experimental-modules .

2017年2月:

https://medium.com/@jasnell/an-update-on-es6-modules-in-node-js-42c958b890c#.6ye7mtn37

NodeJS伙计们认为最糟糕的解决方案是使用.mjs文件扩展名。得出的结论是:

换句话说,给定两个文件foo.jsbar.mjs,using import * from 'foo'将被foo.js视为CommonJS,而import * from 'bar' 将被bar.mjs视为ES6模块

至于时间表...

在当前时间点上,在Node.js甚至开始研究可支持的ES6模块实现之前,ES6和虚拟机方面仍需要解决许多规范和实现问题。工作仍在进行中,但将需要一些时间-我们目前至少需要一年左右的时间。

2016年10月:

Node.JS的开发人员之一最近参加了TC-39会议,并撰写了一篇关于实现Node.JS的阻止程序的绝妙文章:

https://hackernoon.com/node-js-tc-39-and-modules-a1118aecf95e

基本的收获是:

  • 对ES模块进行静态分析,对CommonJS进行评估
  • CommonJS模块允许猴子补丁导出,而ES模块目前不支持
  • 如果没有某种形式的用户输入,很难检测出什么是ES模块以及什么是CommonJS,但是他们正在尝试。
  • *.mjs 似乎是最可能的解决方案,除非他们可以在无需用户输入的情况下准确检测出ES模块

-原始答案-

这已经很长时间了。最重要的是,是的,Node最终将支持导入/导出模块的ES2015语法-最有可能在加载模块规范最终确定并同意时。

这是一个很好的概述 NodeJS保持。本质上,他们需要确保新规范适用于主要是有条件的,同步加载的Node以及主要是异步的HTML。

目前尚无人知道,但我想Node除了支持动态加载import/export的新功能外,还将支持静态System.import加载-同时仍保留require旧代码。

以下是一些有关Node如何实现此目标的建议:


38
关于.mjs扩展名:We have affectionately called these “Michael Jackson Script” files in the past。以防万一您在JS演讲中听到有人谈论流行歌手。
犹太人'17

1
我不明白为什么更改导入语法还不够。一种导入es的语法(“正确的”一种)和一种导入cjs的语法?换句话说,给定两个文件foo.js和bar.js, import * from 'foo'会将foo.js视为CommonJS import * as bar from 'bar'会将bar.js视为ES6模块有人可以解释吗?
Corey Alix

1
为了支持环境,通常不会更改@CoreyAlix语法。毕竟,这实际上只会影响Node。而且,语法有点不直观。如何使用您建议的语法访问导出?
CodingIntrigue

要明确的是,这不是“我的”建议,我正在复制打字稿已经在做的事情。要回答您的问题,请使用“ bar”访问导出:bar.foobar()从“ ./foo”导入{foo作为Foo}是识别ES6模块的机制。var Foo = require(“ ./ foo”)是用于识别CJS模块的机制。在Typescript中,commonjs输出如下所示:var mod1_1 = require(“ ./ mod1”); exports.mod1 = mod1; ES6的输出如下所示:从“ ./mod1”导入{mod1};出口{mod1}
Corey Alix

1
在这个答案的Node 10更新中,我真的很有趣。该功能是否已实现剪切,还是仍在标记后面?
dcorking
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.