commonjs的myRequire

// 分析模块加载的流程
// 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);

 

posted @ 2025-12-10 11:35  jerry-mengjie  阅读(0)  评论(0)    收藏  举报