内容简介:本文于2019-04-23由Dr. Axel博士发表在个人网站2ality,全文对Node.js12中模块的新特性做了详细的分析解读。Node.js 12(于2019-04-23发布)为ECMAScript模块带来了改进的支持。它实施了去年年底发布的计划的第二阶段。目前,这种支持可以在继续阅读以了解这种对ECMAScript模块的新支持是如何工作的。
本文于2019-04-23由Dr. Axel博士发表在个人网站2ality,全文对Node.js12中模块的新特性做了详细的分析解读。
- 原文: 2ality.com/2019/04/nod…
- 译者:李初五
Node.js 12(于2019-04-23发布)为ECMAScript模块带来了改进的支持。它实施了去年年底发布的计划的第二阶段。目前,这种支持可以在 experimental-modules
获得。
继续阅读以了解这种对ECMAScript模块的新支持是如何工作的。
简要说明:文件扩展名.mjs更方便,但.js也可以为ES模块启用。
1.本篇文章中使用的术语和缩写
- CommonJS模块(CJS):指的是原始的Node.js模块标准。
- ECMAScript模块(ES模块,ESM):指通过ECMAScript规范标准化的模块。
- package.prop是指prop的package.json。
2.模块说明符
模块说明符是标识模块的字符串。它们在CommonJS模块和ES模块中的工作方式略有不同。在我们查看差异之前,我们需要了解模块说明符的不同类别。
2.1 模块说明符的类别
在ES模块中,我们区分以下类别的说明符。这些类别源自CommonJS模块。
- 相对路径:以点开头。例:
./some/other/module.mjs ../../lib/counter.mjs 复制代码
- 绝对路径:以斜杠开头。例:
/home/jane/file-tools.mjs 复制代码
- URL:包括协议(从技术上讲,路径也是URL)。例:
'https://example.com/some-module.mjs' 'file:///home/john/tmp/main.mjs' 复制代码
- 裸路径:不以点,斜杠或协议开头,并且由没有扩展名的单个文件名组成。例子:
'lodash' 'the-package' 复制代码
- 深度导入路径:以裸路径开始,至少有一个斜杠。例:
'the-package/dist/the-module.mjs' 复制代码
2.2 CommonJS模块说明符
这是CommonJS处理模块说明符的方式:
- CommonJS不支持URL作为说明符。
- 相对路径和绝对路径按预期处理。
- 您可以将目录foo作为模块加载:
- 如果有文件 foo/index.js
- 如果存在foo/package.json其属性"main"指向模块文件的文件。
- 根据node_modules找到的目录解析裸路径和深度导入路径:
- 与导入模块位于同一目录中
- 在该目录的父级中
- 其它。
- 如果说明符X未引用文件,则系统会尝试使用说明符
X.js
,X.json
和X.node
。
此外,CommonJS模块可以访问两个特殊的模块全局变量:
- __filename:包含当前模块的路径。
- __dirname:包含当前模块的父目录的路径。
本节的来源:Node.js文档的“模块”页面。
2.3 Node.js中的ES模块说明符
- 除裸路径外,所有说明符都必须引用实际文件。与CommonJS相比,ESM不会添加缺少的文件扩展名。
- 仅file:支持URL说明符的协议。
- 目前不支持绝对路径。作为解决方法,您可以使用以file:///。开头的URL 。
- 相对路径在Web浏览器中被解析 - 相对于当前模块的路径。
- 裸路径相对于node_modules目录进行解析。裸路径引用的模块通过package.main(类似于CJS)指定。
- 深度导入路径也相对于node_modules目录进行解析。
- 不支持导入目录。换句话说,既不能使用package.main(只能用于packages)也不能通过index.*工作。
所有内置的Node.js模块都可以通过裸路径获得,并命名为ESM导出。例如:
import * as path from 'path'; import * as assert from 'assert'; assert.equal( path.join('a/b/c', '../d'), 'a/b/d'); 复制代码
2.4 文件扩展名
Node.js支持以下默认文件扩展名:
-
mjs 用于ES模块
-
cjs 用于CommonJS模块 文件扩展名.js代表ESM或CommonJS。它是哪一个,取决于package.type,它有两个设置:
-
commonjs(默认值):扩展名为.js或没有扩展名的文件被解析为CommonJS。
"type": "commonjs" 复制代码
-
module:具有扩展名.js或没有扩展名的文件被解析为ESM。
"type": "module" 复制代码
要查找package.json给定文件,Node.js将在与文件,父目录等相同的目录中进行搜索。
2.5将非文件源代码解释为CommonJS或ESM
并非所有Node.js执行的源代码都来自文件。你也可以通过stdin --eval和它发送代码--print。命令行选项--input-type允许您指定如何解释此类代码:
- 作为CommonJS(默认): --input-type=commonjs
- 作为ESM: --input-type=module
3. 互操作能力
3.1 从ESM导入CommonJS
目前,有两种从ES模块导入CommonJS模块的选项。
考虑以下CommonJS模块。
// common.cjs module.exports = { foo: 123, }; 复制代码
第一个选项是默认导入它(将来可能会添加对命名导入的支持):
// es1.mjs import * as assert from 'assert'; import common from './common.cjs'; // default import assert.equal(common.foo, 123); 复制代码
第二种选择是使用createRequire():
// es2.mjs import * as assert from 'assert'; import {createRequire} from 'module'; const require = createRequire(import.meta.url); const common = require('./common.cjs'); assert.equal(common.foo, 123); 复制代码
3.2 从CommonJS导入ESM
如果要从CommonJS模块导入ES模块,可以使用该import()运算符。
例如,采用以下ES模块:
// es.mjs export const bar = 'abc'; 复制代码
这里我们从CommonJS模块导入它:
// common.cjs const assert = require('assert'); async function main() { const es = await import('./es.mjs'); assert.equal(es.bar, 'abc'); } main(); 复制代码
4. 各种其他功能
4.1 import.meta.url
鉴于 __filename和 __dirname在ES模块不可用,我们需要一个替代方案。import.meta.url是另一种选择。它包含file:具有绝对路径的URL。例如:
'file:///Users/rauschma/my-module.mjs' 复制代码
注意:url.fileURLToPath()用于提取路径 - new URL().pathname并不是总可以正常运行:
import * as assert from 'assert'; import {fileURLToPath} from 'url'; //::::: Unix ::::: const urlStr1 = 'file:///tmp/with%20space.txt'; assert.equal( new URL(urlStr1).pathname, '/tmp/with%20space.txt'); assert.equal( fileURLToPath(urlStr1), '/tmp/with space.txt'); const urlStr2 = 'file:///home/thor/Mj%C3%B6lnir.txt'; assert.equal( new URL(urlStr2).pathname, '/home/thor/Mj%C3%B6lnir.txt'); assert.equal( fileURLToPath(urlStr2), '/home/thor/Mjölnir.txt'); //::::: Windows ::::: const urlStr3 = 'file:///C:/dir/'; assert.equal( new URL(urlStr3).pathname, '/C:/dir/'); assert.equal( fileURLToPath(urlStr3), 'C:\\dir\\'); 复制代码
下一节演示使用import.meta.url和url.fileURLToPath()。
反过来想url.fileURLToPath()是url.pathToFileURL():它将路径转换为文件URL。
4.2 fs.promises
fs.promises包含fsAPI 的promisified版本并按预期工作
import {fileURLToPath} from 'url'; import {promises as fs} from 'fs'; async function main() { // The path of the current module const pathname = fileURLToPath(import.meta.url); const str = await fs.readFile(pathname, {encoding: 'UTF-8'}); console.log(str); } main(); 复制代码
4.3 --experimental-json-modules
使用该标志--experimental-json-modules,Node.js将.json文件加载为JSON。
以JSON文件为例data.json:
{ "first": "Jane", "last": "Doe" } 复制代码
可以从ES模块导入它,如下所示(如果同时使用ESM和JSON模块的标志):
import * as assert from 'assert'; import data from './data.json'; assert.deepEqual( data, {first: "Jane", last: "Doe"}); 复制代码
5.npm上的ES模块
目前,npm上的ES模块引用有以下两种方式可以选择:
require('mylib') import from 'mylib
你不能两者兼顾(深度导入路径是合理的解决方法)。我们正在努力改变这一状况。它可能会通过package.main更强大的功能来完成。
在该功能准备就绪之前,对处理该功能的人员有以下要求:
“在解决之前,请不要发布任何供Node.js使用的ES模块包。” 复制代码
6.在Node.js上使用ES模块
从Node.js 12开始,Node.js上使用ES模块有以下选项:
-
library:ESM由John-David Dalton维护。esm还支持旧版本的Node.js.
-
Flag--experimental-modules
当Node.js 12达到LTS状态时,可能会在2019年10月删除ESM支持的标志。
最后欢迎大家关注公众号前端小苑,我会定期在这里发表原创文章。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 让 js 模块支持 typescript
- 为nginx添加SSL支持模块
- Chrome 63 Beta:支持动态模块导入,新增设备内存 API
- Go 1.11 正式发布:添加对模块 "modules" 的初步支持
- gf v0.97beta 发布,更多模块支持、功能改进及文档完善
- GoLand 2018.2.2 正式发布,支持 Go 新版中的模块功能
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。