node模块加载浅析
通过分析require 加载模块流程,实现简易版本,本文环境 node v15.4.0
调试数据
// main.js
require('./test');
// test.js
let a=1;
console.log(this===module.exports,'this');
module.exports=a;
** 提示: vscode 断点调试要进入源码文件需要将 launch.json 中 skipFiles
文件注释。
// "skipFiles": [
// "<node_internals>/**"
// ],
通过在main.js
中打断点,进入require
函数。
- 首先会调用
makeRequireFunction
函数中 require方法,传递当前路径./test
// https://github.com/nodejs/node/blob/v15.4.0/lib/internal/modules/cjs/helpers.js#L48
(function (exports, require, module, process, internalBinding) {
'use strict';
function makeRequireFunction(mod) {
const Module = mod.constructor;
function require(path) {
return mod.require(path);
}
}
})
- 然后我们进入
Module
构造函数原型方法require 方法中
// https://github.com/nodejs/node/blob/v15.4.0/lib/internal/modules/cjs/loader.js#L989
Module.prototype.require = function(id) {
// 忽略其它校验条件
return Module._load(id, this, /* isMain */ false);
};
此时我们先暂停探究_load
方法实现细节,来去看看Module
构造函数结构可能对后面会有一个宏观的理解。
Module 源码戳这里
function Module(id = '', parent) {
this.id = id;
this.path = path.dirname(id);
this.exports = {
};
}
Module._cache = ObjectCreate(null); // ObjectCreate --> Object.create
Module._pathCache = ObjectCreate(null);
Module._extensions = ObjectCreate(null);
Module._load=function(request, parent, isMain){
}
Module._resolveFilename=function(request, parent, isMain){
};
Module.prototype.load=function(filename){
}
Module.prototype._compile = function(content, filename) {
}
Module._extensions