我们宣布在Node.js中支持ECMAScript模块

Node.js 13.2.0随附ECMAScript支持,这些模块以导入和导出语法闻名。 以前,此功能位于--experimental-modules标志的后面,该标志不再需要。 但是,该实现仍处于试验阶段,可能会发生变化。


来自翻译者:期待已久的功能最终将使我们能够使用现代浏览器中已经可用的标准模块化语法,现在也可以使用Node.js中的无标志和编译器


激活方式


在以下情况下,Node.js将代码作为ES模块处理:


  • 扩展名为.mjs文件
  • 带有.js扩展名或根本没有扩展名的文件,前提是最接近它们的父package.json包含值"type": "module"
  • 通过—-eval或STDIN参数传递的代码,以及—-eval —-input-type=module标志

在所有其他情况下,该代码将被视为CommonJS。 这适用于最近的package.json不带"type": "module" .js文件,以及不指定--input-type而通过命令行传递的代码。 这样做是为了保持向后兼容性。 但是,由于我们现在有两种模块,CommonJS和ES,因此最好明确指定模块的类型。


您可以使用以下功能将代码明确标记为CommonJS:


  • 扩展名为.cjs文件
  • 带有扩展名.js或根本没有扩展名的文件,但前提是最接近的父package.json包含值"type": "“commonjs”"
  • 通过--eval或STDIN参数传递的代码,带有显式标志--input-type=commonjs

要了解有关这些功能的更多信息,请参见“包范围和文件扩展名”文档部分以及 --input-type


语法导入和导出


在ES模块的上下文中,可以使用import指向其他Javascript文件。 可以采用以下格式之一指定它们:


  • 相对网址: "./file.mjs"
  • 绝对URL c file:// ,例如, "file:///opt/app/file.mjs"
  • 套件名称: "es-module-package"
  • 包内文件的路径: "es-module-package/lib/file.mjs"

在导入中,可以使用默认值( import _ from "es-module-package" )和命名值( import { shuffle } from "es-module-package" ),也可以将所有内容作为一个命名空间import * as fs from "fs"import * as fs from "fs" 。 所有内置的Node.js软件包(例如fspath )都支持所有三种类型的导入。


指向CommonJS代码的导入(即,所有当前 requiremodule.exports为Node.js编写的JavaScript)只能使用默认选项( import _ from "commonjs-package" )。


导入其他文件格式(例如JSON和WASM)仍处于实验阶段,并且分别需要标志--experimental-json-modules--experimental-wasm-modules 。 但是,您可以使用module.createRequire API下载这些文件,该API无需附加标志即可使用。


在ES模块中,可以使用export关键字导出默认值和命名值。


带有import()动态表达式可用于从CommonJS或ES代码加载ES模块。 请注意, import()不会返回模块,而是返回其Promise(承诺)。


import.meta.urlimport.meta.url提供import.meta.url ,其中包含当前ES模块的绝对URL。


文件和package.json中的新“类型”字段


在项目的package.json中添加"type": "module" ,Node.js将开始将项目的所有.js文件视为ES模块。


如果您项目中的某些文件仍使用CommonJS并且无法一次迁移整个项目,则可以使用.cjs扩展.cjs为此代码,或者将其放在单独的目录中,然后添加包含{ "type": "commonjs" } ,它告诉Node.js应该将其视为CommonJS。


对于每个下载的文件,Node.js都会在包含该文件的目录中查看package.json ,然后再进行上一层操作,依此类推,直到到达根目录为止。 该机制类似于 Babel .babelrc文件的方式 。 这种方法允许Node.js将package.json用作有关包和配置的各种元数据的来源,类似于它在Babel和其他工具中的工作方式。


我们建议所有程序包开发人员都指定一个type字段,即使在该commonjs中编写了commonjs


程序包入口点和package.json中的“导出”字段


现在,我们有两个字段用于指定包的入口点mainexports 。 所有版本的Node.js都支持main字段,但是其功能受到限制:使用它,您只能在包中定义一个主要入口点。 新的exports字段还允许您定义主入口点以及其他路径。 这为包提供了额外的封装,其中仅显式exports路径可用于从包外部导入。 exports适用于CommonJS和ES两种模块,无论它们是通过require还是import来使用的。


此功能将允许pkg/feature类型导入指向诸如./node_modules/pkg/esm/feature.js之类的真实路径。 另外,如果导入引用未在pkg/esm/feature.js指定的pkg/esm/feature.js ,则Node.js将引发错误。


另外一个仍处于试验阶段的功能性条件导出提供了针对不同环境导出不同文件的能力。 这将允许程序包为CommonJS代码提供调用require("pkg")权限,并允许ES模块代码通过import "pkg"方式import "pkg" ,尽管编写这样的程序包并非没有其他问题 。 您可以使用—-experimental-conditional-exports标志启用条件导出。


新模块的主要作用


所需的文件扩展名


使用导入时,必须指定文件扩展名。 从目录导入索引文件时,还必须完全指定文件的路径,即“ ./startup/index.js”。


此行为与在不进行其他配置的情况下访问常规服务器时导入在浏览器中的工作方式一致。


module.exportsexportsmodule.exports__filename__dirname


这些来自CommonJS的值在ES模块的上下文中不可用。 但是,可以通过module.createRequire()require导入到ES模块中。 等效的__filename__dirname可以从import.meta.url获得。


创建包


目前,我们建议程序包作者对其Node.js项目使用完全CommonJS或完全ES模块。 Node.js的模块工作组将继续寻找改进对双包的支持的方法,其中CommonJS用于旧用户,而ES模块用于新用户。 现在有条件出口仍处于试验阶段,我们希望在2020年1月或更早之前推出此功能或其替代产品。


要了解有关此内容的更多信息,请参阅我们的示例和建议以创建双重CommonJS / ES模块软件包。


接下来会发生什么


装载机。 有关API的工作将继续进行,以编写自定义加载程序,在运行时实现模块蒸发,重新定义导入路径(包或单个文件)以及检测代码。 实验性API(在—-experimental-loader标志下可用)在我们将其从标志中删除之前会进行重大更改。


双CommonJS / ES模块软件包。 我们希望提供一种发布软件包的标准方法,该软件包可以通过CommonJS中的require和ES模块中的import使用。 我们在文档中有关于此的更多信息。 我们计划在2020年1月底(如果更早)完成工作并退出船旗。


仅此而已! 我们希望ECMAScript对模块的支持使Node.js更接近JavaScript标准,并带来新功能以实现整个JavaScript生态系统的兼容性。 改善模块支持的工作流程已在此处公开完成: https : //github.com/nodejs/modules

Source: https://habr.com/ru/post/zh-CN477168/


All Articles