2022-04-13-Nodejs模块加载研究
1. 这个功能是什么#
NodeJS 中有两种模块加载方式:CommonJS,ECMAScript modules;前者为 NodeJS 内部实现,ES Modules 为 JS 标准加载方式。
1.1. CommonJS#
在 Node.js 模块系统中,每个文件都被视为一个单独的模块。
1.2. ECMAScript modules#
ECMAScript 模块是打包 JavaScript 代码以供重用的官方标准格式。使用 import 和 export 导入导出模块。
Node.js 默认将 JavaScript 代码视为 CommonJS 模块。可以通过.mjs 文件扩展名,package.json ‘type’字段,将 JavaScript 代码将 ECMAScript 视为模块
2. 这个功能如何实现#
2.1. CommonJS#
2.1.1. 模块包装器#
Nodejs 中的模块是可执行的,nodejs 使用类似以下语法将模块封装为函数
1 | (function(exports, require, module, __filename, __dirname) { |
通过这种方式
- 它将顶级变量(用 var、const 或 let 定义)的作用域限定在模块上,而不是全局对象上。
- 通过将模块内的数据导出到对象(exports,module),供外部调用者使用,同时引入了在模块内可使用的变量(__filename, __dirname)
3. 这个功能相关的参与者与接口#
3.1. CommonJS 接口#
3.1.1. 3.2.1.#
3.1.2. __dirname#
文件绝对路径所在的目录
3.1.3. __filename#
文件的绝对路径
3.1.4. exports module.exports#
exports 是 module.exports 的简写,两者关系如下相关资料
- exports 只能使用语法来向外暴露内部变量:如http://exports.xxx = xxx;
- module.exports 既可以通过语法,也可以直接赋值一个对象。
伪代码实现说明
1 | function require(/* ... */) { |
建议不要使用 exports,因为 module.exports 都能做,还不会出错
3.2. ES modules#
3.2.1. specifier (区分符)#
区分符 specifier 指以下文句中的 ‘path’
1 | import { sep } from 'path' |
specifier 有如下形式
- 相对路径。它们引用相对于导入文件位置的路径。对于这些文件,文件扩展名总是必需的。如 ‘./startup.js’ or ‘../config.mjs’
- 包名。它们可以通过包名引用包的主入口点,也可以根据示例分别引用以包名作为前缀的包内的特定特性模块。
- 绝对路径。直接和显式地引用了一个完整的路径。’file:///opt/nodejs/config.js’.
4. CommonJS 与 ECMAScript modules 互操作#
4.1. import#
import 语句(import * from ‘xxx’)只允许在 ES 模块中使用,但在 CommonJS 中支持动态 import()表达式来加载 ES 模块。
4.2. require#
只用来加载 CommonJS 模块
4.3. CommonJS Namespaces#
CommonJS 模块由一个 module.exports 对象组成。可以导出任何类型的对象
5. 相关资料#
- CommonJS
http://nodejs.cn/api/modules.html - ECMAScript modules
http://nodejs.cn/api/esm.html
6. 示例#
6.1. commonjs#
6.1.1. 使用 module.exports 导出#
- 库文件
1 | function add(a, b) { |
- 主函数文件
1 | let add_commonjs_modules_exports = require('./modules/add_commonjs_modules_exports.js'); |
6.1.2. 使用 exports 导出#
- 给 exports 的成员赋值
- 库文件
1 | function add(a, b) { |
- 主函数文件
1 | let add_commonjs_exports = require('./modules/add_commonjs_exports.js'); |
- 给 exports 赋值(此方法无法导出)
- 库文件
1 | function add(a, b) { |
- 主函数文件
1 | let add_commonjs_exports_error = require('./modules/add_commonjs_exports_error.js'); |
6.2. ESModules#
6.2.1. 使用 export 导出,注意其中 default 使用#
- 库文件
1 | export function add(a, b) { |
- 主函数文件
1 | import * as fun from './modules/add_ES_export.mjs'; |
6.3. 用 import 加载 commonjs 模块#
- 库文件
1 | function add(a, b) { |
- 主程序文件
1 | import * as c from './modules/add_commonjs_modules_exports.js'; //es中调用commonjs模块 |
2022-04-13-Nodejs模块加载研究