前言:
今天带给大家手写 require 函数代码,希望对大家有所帮助。
代码:
// 1. 现将 .a 文件转化为绝对路径
// 2. 读取这个文件,需要增加一个函数,函数内部需要返回 module.exports
// 3. 让函数执行
// 4. new Module 创建模块,根据文件名来创建, exports id
// -- module.load 加载模块
// -- Module._extensions 代表一个对象,对象上放着很多处理方法
// -- exports require module __filename
// 5. 最终返回 module.exports
let path = require("path");
let fs = require("fs");
let vm = require("vm");
function Module(id) {
this.id = id;
this.exports = {};
}
function resolveFileName(filename) {
// 先将路径 转化为 绝对路径
let r = path.resolve(__dirname, filename);
// 需要看一下 文件路径是否存在,如果不存在,尝试添加 .js 和 .json 后缀
let isExists = fs.existsSync(r);
if (isExists) {
return r;
} else {
let keys = Object.keys(Module._extensions);
for (let i = 0; i < keys.length; i++) {
let ext = keys[i];
let tryFileName = r + ext;
if (fs.existsSync(tryFileName)) {
return tryFileName;
}
}
throw new Error("module not found!");
}
}
function tryModuleLoad(module) {
// 获取文件的后缀名
let extname = path.extname(module.id); // a.js
Module._extensions[extname](module); // 不同后缀执行不同的加载逻辑
}
let wrapper = [
"(function(exports,require,module,__filename,__dirname){",
"\n})",
];
Module._extensions = {
".js"(module) {
let scripts = fs.readFileSync(module.id, "utf8");
let fnStr = wrapper[0] + scripts + wrapper[1];
let fn = vm.runInThisContext(fnStr);
let exports = module.exports; // exports 和 module.exports
// 不能直接改变 exports 他是不会影响 module.exports 的
fn.call(
exports,
exports,
req,
module,
module.id,
path.dirname(module.id)
);
},
".json"(module) {
let scripts = fs.readFileSync(module.id, "utf8");
try {
module.exports = JSON.parse(scripts);
} catch (err) {
console.log("转换 失败!", err);
}
},
};
Module._cache = {};
function req(filename) {
let id = resolveFileName(filename);
let cacheModule = Module._cache[id];
if (cacheModule) {
console.log("缓存了");
return cacheModule.exports;
}
let module = new Module(id);
// 缓存模块
Module._cache[id] = module;
// 加载这个模块
tryModuleLoad(module);
return module.exports;
}
let str = req("./a");
let strr = req("./a");
console.log(req("./a.json"));
console.log(str, strr);