模块分类
- 内置模块:Node 源码编译时写入到二进制文件中
- 文件模块:代码运行时,动静加载
加载流程
- 路径分析:根据标识符确定模块地位(门路标识符、非门路标识符)
- 文件定位:确定指标模块中具体的文件及文件类型(存在 ’m1’ 模块,导入时应用 require(‘m1’) 语法,应用 m1.js->m1.json->m1.node 的程序,如果都没找到,会被当做一个目录,查找 package.json 文件,应用 JOSN.parse() 解析。接下来会找 main.js->main.json->main.node。将 index 作为指标模块中的具体文件名称)
- 编译执行:采纳对应的形式实现文件的编译执行 (将某个具体类型的文件依照相应的形式进行编译和执行,创立新对象,按门路载入,实现编译执行,返回可用 exports 对象)
缓存优先准则
- 进步模块加载速度
- 以后模块不存在,则经验一次残缺加载流程
- 模块加载实现后,应用门路作为索引进行缓存
模块加载模仿实现
外围逻辑
- 路径分析
- 缓存优化
- 文件定位
- 编译执行
依据下面的加载流程特色模仿实现
const fs = require("fs");
const path = require("path");
const vm = require("vm");
function Module(id) {
this.id = id;
this.exports = {};}
// 静态方法
Module._resolveFilename = function (filename) {
// 利用 path 将 filename 转为绝对路径
let absPath = path.resolve(__dirname, filename);
console.log(absPath);
// 判断以后门路对应的内容是否存在
if (fs.existsSync(absPath)) {
// 条件成立阐明 absPath 对应的内容是存在的
return absPath;
} else {
// 依据文件定位的程序顺次去找
let suffix = Object.keys(Module.__extensions);
for (var i = 0; i < suffix.length; i++) {
// 拼接
let newPath = absPath + suffix[i];
if (fs.existsSync(newPath)) {return newPath;}
}
}
throw new Error(`${filename} is not exists`);
};
Module.__extensions = {".js"(module) {
// 读取
let content = fs.readFileSync(module.id, "utf-8");
// 包装
content = Module.wrapper[0] + content + Module.wrapper[1];
// 应用 vm 执行
let compileFn = vm.runInThisContext(content); // 转换成一个可执行匿名函数
// 筹备参数的值
let exports = module.exports;
let dirname = path.dirname(module.id);
let filename = module.id;
// 调用
compileFn.call(exports, exports, myRequire, module, filename, dirname);
},
".json"(module) {
// 读取而后格式化
let content = JSON.parse(fs.readFileSync(module.id, "utf-8"));
module.exports = content;
},
};
Module.wrapper = ["(function(exports,require,module,__filename,__dirname){",
"})",
];
Module._cache = {};
Module.prototype.load = function () {let extname = path.extname(this.id);
console.log("extname", extname);
Module.__extensions[extname](this);
};
function myRequire(filename) {
// 1,获取绝对路径
let modulePath = Module._resolveFilename(filename);
// 2, 实现缓存优先
let cacheModule = Module._cache[modulePath];
if (cacheModule) {return cacheModule.exports;}
// 3 创立空对象加载指标模块
let module = new Module(modulePath);
// 4, 缓存曾经加载的模块
Module._cache[modulePath] = module;
// 5,执行加载(编译执行 )
module.load();
// 6 , 返回数据
return module.exports;
}
let obj = myRequire("./m");
console.log(obj);