time: 2020.12.21
author: heyunjiang
nodejs 默认使用 commonjs 模块,这里列举模块加载和使用方式
模块缓存规则
:不同目录加载的文件,最终缓存的模块名字不一样,是根据绝对路径来计算缓存规则的,也就是会根据不同目录执行多次;依赖缓存名为当前模块的 node_modules 目录下exports.
,它是 module.exports 的简写.js .json .node
模块包装器
:nodejs 模块的执行是被 nodejs 封装在限定的一个函数中,函数参数提供了 exports, module, require, __filename, __dirnamerequire.cache
用于查看和处理缓存文件nodejs 模块包装器
(function(exports, module, require, __filename, __dirname) {
// 模块代码执行区域
})
module 对象格式
{
id: '.',
path: '/absolute/path/to',
exports: {},
parent: null,
filename: '/absolute/path/to/entry.js',
loaded: false,
children: [],
paths:
[ '/absolute/path/to/node_modules',
'/absolute/path/node_modules',
'/absolute/node_modules',
'/node_modules' ]
}
require 的模拟实现方式(webpack 就是这么模拟实现的)
function require(/* ... */) {
const module = { exports: {} };
((module, exports) => {
// 模块代码在这。在这个例子中,定义了一个函数。
function someFunc() {}
exports = someFunc;
// 此时,exports 不再是一个 module.exports 的快捷方式,
// 且这个模块依然导出一个空的默认对象。
module.exports = someFunc;
// 此时,该模块导出 someFunc,而不是默认对象。
})(module, module.exports);
return module.exports;
}
该 module 对象与模块包装器中的 module 不同,当前是 nodejs 的核心模块 module,需要通过 require or import 使用
require('module').buildinModules
const sourcemap = new SourceMap(payload) sourcemap.payload sourcemap.findEntry(lineNumber, columnNumber)
nodejs 内置了对 sourcemap 的操作
commonjs 模块是存在缓存中的,可以通过 require.cache
查看缓存的文件,根据绝对路径判断,多次引用相同的模块,该模块只会在第一次时被执行,也就是说共享的同一个对象;
es6 模块是属于对原有模块的引用
commonjs 模块输出 module 对象,会被缓存;es6 是通过 export 直接输出代码接口的引用。
cjs 是 nodejs 执行的模块,esm 是浏览器和 nodejs 都可以执行的模块
commonjs 模块是在运行时(require 不受限制于顶层)加载的,之前可能就执行过其他代码了。
初次加载会执行模块代码,然后生成模块对象并缓存起来,访问时通过读取模块的 exports 属性,也就是说不能提前在代码层面做解释执行优化;后续会总缓存的 module 对象读取
es6 是在模块解析阶段生成 export 接口,其他模块对当前模块属性接口的引用。模块会在 import 阶段解析之后,就立即执行
归纳:cjs 是运行时加载,而 esm 是在代码解析阶段加载