-
Notifications
You must be signed in to change notification settings - Fork 20
Open
Description
为什么node不支持ESM(ECMAScript module)?
- require vs ES6 import nodejs/help#53
- https://stackoverflow.com/questions/36901147/es2015-import-not-working-in-node-v6-0-0-with-with-harmony-modules-option
- [译]深入研究-ES modules(漫画版) 【转】 #620
- ES6模块和require的差异
-
- Node.js和TC-39对“模块”是什么,如何定义以及如何将它们加载到内存和使用中有着截然不同的想法。
-
- node的require实现的原理是:
-
-
-
- 执行的时候,通过require函数确定文件的绝对路径
-
-
-
-
-
- 通过绝对路径匹配文件,然后加载整个文件到内存中,然后parser
-
-
-
-
-
- 使用一个函数包裹模块代码字符串,比如:
-
-
// 包裹前
const m = 1;
module.exports.m = m;
// 包裹后
function(exports,require,module,__ filename,__ dirname){
const m = 1;
module.exports.m = m;
}-
-
-
- 使用VM虚拟机进行执行模块文件
-
-
-
- 所以,在执行包裹函数前,无法预知该模块导出了什么,依赖树是怎样的。这也是跟ES6模块的根本区别所在。而ESM在执行前,已经通过parse建立module map,链接map到各个模块的内存中,执行除了导出模块内部代码外的所有父级执行域代码。就是ESM导入模块前,就已经执行了所有依赖树的全局作用域代码,获得了各个作用域的变量池
- 首先node的require够用
- 可以通过
node --v8-options | grep harmony获取node最新特性 - 网络加载问题,这个才是大问题,https://github.com/WICG/import-maps
- node 目前使用
.mjs后缀来兼容ESM - node.js准备在12版内支持,进程:new ESM implementation nodejs/node#26745
ECM的实现
node 如何调用ECM
- 注意文件名后缀是
.mjs和使用--experimental-modules变量 - https://nodejs.org/dist/latest-v12.x/docs/api/esm.html
- 只要有import就会调用那个文件的全局作用域,不管该导入模块有没有执行
- 多次import同一个文件,全局作用域也只运行一次,实现通过module map实现
- 由于import/export指向同一个内存地址,所以可以
import aa from 'aa.mjs直接修改aa的值,然后别的模块引入aa的值的时候也是最新的值
// a.mjs
function aa() {
console.log('aa');
}
export default aa;// b.mjs
import aa from './test.mjs';
aa();console.log('pre cc')
function aa() {
console.log('cc');
}
export default aa;**这里的输出比较有趣,可以看到是import的时候直接运行模块外面的全局代码,然后运行完所有import的代码才执行调用代码
node --experimental-modules bb.mjs
# pre aa
# pre cc
# aa
# cc