在 Node.js 中使用原生的 ES 模块
Posted 前端外刊评论
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在 Node.js 中使用原生的 ES 模块相关的知识,希望对你有一定的参考价值。
本文译自:Using ES modules natively in Node.js,原作者是 Dr. Axel Rauschmayer,圈内称之为"德国阮一峰"。
Node.js 从 8.5.0 开始原生支持 ES 模块,不过还需要通过命令行参数控制。这还得感谢 Bradley Farias 对这个新特性的贡献。
本文就给大家详细讲讲这个特性。
举个栗子
文件结构:
esm-demo/
lib.mjs
main.mjs
lib.mjs
:
exportfunctionadd(x, y) {
return x + y;
}
main.mjs
:
import {add} from'./lib.mjs';
console.log('Result: '+add(2, 3));
运行示例:
$ node --experimental-modules main.mjs
Result: 5
注意注意!
ES 的模块名称:
所有的模块名称都是 URL —— 这对 Node.js 来说引入了新的东西;
文件:最好使用相对的带
.mjs
后缀的路径来引用 ES 模块,这样可以保证对浏览器的兼容。如果不包含后缀名,则模块搜索方式与 CJS 保持一致。如果同时找到了.mjs
和.js
的文件,则使用.mjs
文件;例如:
../util/tools.mjs
类库模块:直接使用模块名,省略扩展名是最佳方式。这能与现阶段类库模块发布的方式保持最好的兼容;
例如:
lodash
如何让
node_modules
里的模块在浏览器里工作还有待研究(不使用 bundler 工具)。一种可选方案是引入类 RequireJS 的配置方式,将裸路径转换到真实路径上。就目前而言,裸路径的模块在浏览器是中是用不了的;
ES 模块的特性:
无法动态引入模块;但是很快就会引入动态操作符
import()
来实现;像
__dirname
和__filename
和这样的元变量将不再提供,有一个新的提案引入将会给 ES 模块提供类似的方式——Domenic Denicola 提出import.meta
。
console.log(import.meta.url);
与 CJS 模块的互操作性
ES 模块可以
import
CJS 模块,但是引入的模块只包含一个default
export——即module.exports
的值。已经开始计划让 CJS 模块输出具名 export(通过在文件开始加编译指令的方式),不过可能实现需要花一些时间。如果你想帮忙,看这里。import fs1 from'fs';
console.log(Object.keys(fs1).length); // 86
import * as fs2 from'fs';
console.log(Object.keys(fs2)); // ['default']
在 ES 模块中不能调用
require()
,主要是因为:路径解析在两种规范中是很不一样的:ESM 不支持
NODE_PATH
和require.extensions
;它的模块标识符永远都是 URL,这会造成小小的区别;为了与浏览器保持最大的兼容性,ES 模块总是异步加载的。这种异步加载的方式与 CJS 通过
require()
同步加载的方式无法很好的在一起工作;同步模块的禁用同样也给在 ES 模块中使用顶级
await
关上了大门(一个目前正在考虑的特性);CJS 无法
require()
ES 模块。原因与上一条提到的类似,同步加载异步的模块各种问题啊。不过也许可以通过import()
来加载 ES 模块。
在老版本的 Node.js 上使用 ES 模块
好吧,如果你想在老的 Node.js 的使用 ES 模块,可以看看 John-David Dalton 的 @std/esm
。
小贴士:只要不使用 unlockables 特性,就可以保证与原生的 ES Module 完全兼容。
FAQ
什么时候可以不借助命令配置就可以使用 ES 模块?
目前的计划是,在 Node.js 10 LTS 版本中可以直接支持 ES 模块;
.mjs
在浏览器中可以工作么?
可以的,只需要提供正确的 Media Type( text/javascript
或者 application/javascript
)即可。 .mjs
标准化和周边工具的升级正在进行中。
文件扩展名 .mjs
是 ES 模块所必须的么?
是的,对于 Node.js 来说是这样的。浏览器不在乎文件扩展名,只关心 Media Type。
为什么 Node.js 需要 .mjs
?
Node.js 本可以检查一个文件是 CJS 模块还是 ES 模块。在选择添加扩展名这个方案之前也讨论过多个其他方案。可以阅读本博的另外一篇了解。每种方案都有其优势和缺点。在我看来, .mjs
是正确的选择。
以上是关于在 Node.js 中使用原生的 ES 模块的主要内容,如果未能解决你的问题,请参考以下文章
使用node.js中fs模块的copyFileSync方法复制文件报错“operation not permitted, copyfile ‘G: est.txt‘ -> ‘G:Trash‘“(代码片
本地 ES 模块(浏览器或 Node.js)的热模块替换*没有* Webpack?没有构建工具
Node.js 全球化 es6 模块以像 ImportScripts 一样工作