Node.js如何加载ECMAScript模块?ES模块加载运行的核心函数是什么?
Node.js加载ECMAScript模块的机制及核心运行函数
一、Node.js如何加载ECMAScript模块?
- 模块识别逻辑:Node.js靠三种方式判断一个文件是不是ES模块:
- 文件后缀直接是
.mjs - 文件后缀为
.js,且所在目录(或往上找最近的)package.json里设置了"type": "module" - 其他兼容ES模块的后缀(比如
.jsx、.tsx,需配合对应的loader处理)
- 文件后缀直接是
- 完整加载流程:分三个阶段逐步执行:
- 构建阶段:解析模块代码,生成模块记录,同时找出所有通过
import声明引入的依赖 - 实例化阶段:递归加载所有依赖模块,在模块之间建立导出-导入的引用绑定——这也是ES模块和CommonJS的核心区别之一,ES模块的导入是动态绑定,不是静态拷贝
- 求值阶段:执行模块的顶层代码,填充导出内容,此时导入方就能访问到模块的导出值
- 构建阶段:解析模块代码,生成模块记录,同时找出所有通过
- 模块路径解析规则:
- 相对路径导入(比如
./utils.js):从当前模块所在目录开始查找 - 绝对路径导入(比如
/home/user/utils.js):直接定位到目标文件 - 裸模块导入(比如
lodash):会依次遍历node_modules目录,读取模块package.json里的main或exports字段找到入口文件
- 相对路径导入(比如
二、ES模块对应的核心运行/加载函数
CommonJS用vm.compileFunction作为核心编译执行工具,而ES模块的核心是Node.js vm模块里的**vm.compileModule和vm.Module类**:
vm.compileModule(code[, options]):专门用来编译ES模块代码,返回一个vm.Module实例,这个实例包含了模块的编译信息- 拿到实例后,需要先调用
module.link(linker)方法解析并链接依赖模块,再调用module.evaluate()执行模块顶层代码,完成求值 - 简单示例:
const vm = require('vm'); const moduleCode = ` export const message = 'Hello ES Module'; `; // 编译ES模块代码 const mod = vm.compileModule(moduleCode); // 链接依赖(此示例无依赖,linker直接抛出错误) mod.link(async (specifier) => { throw new Error(`未找到依赖: ${specifier}`); }); // 执行模块 mod.evaluate(); // 获取模块导出的内容 console.log(mod.namespace.message); // 输出: Hello ES Module
内容的提问来源于stack exchange,提问作者Melab
相关产品推荐
相关产品推荐

