Skip to content

ES6 Module/import/export/require 模块源码和使用相关,以及动态导入import() #633

@cisen

Description

@cisen

为什么node不支持ESM(ECMAScript module)?

// 包裹前
const m = 1; 
module.exports.m = m;
// 包裹后
function(exports,require,module,__ filename,__ dirname){ 
  const m = 1; 
  module.exports.m = m; 
}
        1. 使用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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions