关于commonjs:CommonJS模块分类及加载流程及模块加载模拟实现

39次阅读

共计 2072 个字符,预计需要花费 6 分钟才能阅读完成。

模块分类

  1. 内置模块:Node 源码编译时写入到二进制文件中
  2. 文件模块:代码运行时,动静加载

加载流程

  • 路径分析:根据标识符确定模块地位(门路标识符、非门路标识符)
  • 文件定位:确定指标模块中具体的文件及文件类型(存在 ’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);

正文完
 0