// 分析模块加载的流程
// 1.加载模块 Module._load 加载模块之后 最终返回的就是module.exports
// 2.Module._resolveFilename 解析文件名, 产生一个可读取的文件名 .js? .json?
// 3.Module._cache 如果文件被缓存过 直接拿上一次的返回结果
// 4.如果模块没有加载过,会根据路径创建一个模块 new Module() {id:文件名,exports:导出结果}
// 5.缓存模块为了后续使用
// 6.module.load 加载模块(读文件)
// 7.获取扩展名来调用不同的加载方式
// 8.根据扩展名查找 对应的加载方式 Module._extension
// 9.js的模块主要是读取
// 10.读取文件后包裹函数 , 并且传入五个参数 [ 'exports','require','module','__filename', '__dirname' ]
// 11.执行函数 用户会给module.exports 赋予值
// 12. 因为最终返回的是module.exports 所以可以拿到最终的返回结果
function Module(id) {
this.id = id;
this.exports = {}; // 核心的 ,每个模块的导出结果都在这里
}
Module._cache = {};
Module._extensions = {
".js"(module) {
const content = fs.readFileSync(module.id, "utf8");
let wrapperFn = vm.compileFunction(content, [
"exports",
"require",
"module",
"__filename",
"__dirname",
]);
let exports = module.exports;
let thisValue = exports; // this就是exports
let dirname = path.dirname(module.id);
Reflect.apply(wrapperFn, thisValue, [
exports,
myRequire,
module,
module.id,
dirname,
]); // module.exports = 'abc'
},
".json"(module) {
const content = fs.readFileSync(module.id, "utf8");
module.exports = JSON.parse(content); // 将解析的json 直接替换导出结果
},
};
Module._resolveFilename = function (id) {
const fileUrl = path.resolve(__dirname, id);
if (fs.existsSync(fileUrl)) return fileUrl;
let exts = Reflect.ownKeys(Module._extensions);
for (let i = 0; i < exts.length; i++) {
const fileUrl = path.resolve(__dirname, id + exts[i]);
if (fs.existsSync(fileUrl)) return fileUrl;
}
throw new Error("module not found");
};
Module.prototype.load = function (filename) {
let ext = path.extname(filename);
Module._extensions[ext](this); // 根据扩展名自动处理 策略模式
};
function myRequire(id) {
// 1.解析文件名
let filepath = Module._resolveFilename(id);
// 2.构建模块
let cacheModule = Module._cache[filepath];
if (cacheModule) {
return cacheModule.exports;
}
const module = new Module(filepath);
Module._cache[filepath] = module; // 缓存当前模块
// 3.加载模块 读取文件 + 执行操作
module.load(filepath);
// 4.返回结果
return module.exports;
}
// 自己实现了一个commonjs模块加载, 读取文件,将结果赋予给module.exports 上即可
let content = require("./module.json");
console.log(content);