美文网首页
手动实现commonjs规范

手动实现commonjs规范

作者: TerdShow | 来源:发表于2019-10-03 01:28 被阅读0次

核心逻辑
require()
1.Module._resolveFilename 解析文件的名字 获取文件的绝对路径
2.module.load(filename); 加载模块
3.fs.readFileSync(filename, 'utf8'); 同步的读取文件内容
4.加函数
5.让函数执行将 module.exports 传入给用 用户会给moudle.exports 赋值
6.把module.exports返回

// 1) node模块 会按照后缀名查找 .js 文件是否存在 .json文件
const path = require("path");
const fs = require("fs");
const vm = require("vm");
function Module(id) {
  this.id = id;
  this.exports = {}; // 模块的结果
}
Module.wrapper = [
  "(function(module,exports,require,__filename,__dirname){",
  "})"
];
Module.extensions = {
  ".js"(module) {
    let script = fs.readFileSync(module.id, "utf8");
    let fnStr = Module.wrapper[0] + script + Module.wrapper[1];
    let fn = vm.runInThisContext(fnStr); // 让字符串变成js代码
    // 第一个参数是改变this指向  module  module.exports
    fn.call(
      module.exports,
      module,
      module.exports,
      req,
      module.id,
      path.dirname(module.id)
    );
    // exports 已经让用户更改了
  }, // js需要将exports 传入给用户 用户自己赋值
  ".json"(module) {
    // 解析后 node默认会赋值
    let script = fs.readFileSync(module.id, "utf8");
    module.exports = JSON.parse(script);
  }
};
// 给你一个相对路径 解析成绝对路径
Module.resolveFileName = function(filename) {
  // 1) 把相对路径转化成绝对路口 默认会先判断一下是否是绝对路径
  let absPath = path.resolve(__dirname, filename);
  let flag = fs.existsSync(absPath); // 判断文件是否存在 异步方法被废弃
  let current = absPath; // 默认是当前路径
  if (!flag) {
    let keys = Object.keys(Module.extensions);
    for (let i = 0; i < keys.length; i++) {
      current = absPath + keys[i]; // 当前找到的文件路径
      let flag = fs.existsSync(current);
      if (flag) {
        break;
      } else {
        current = null;
      }
    }
  }
  if (!current) {
    // 如果没有 说明加了后缀文件还是不存在
    throw new Error("文件不存在");
  }
  return current; // 返回文件的路径
};
Module.prototype.load = function() {
  // 模块加载就是读取文件的内容
  let ext = path.extname(this.id);
  Module.extensions[ext](this); // 根据不同的后缀 调用不同的处理方法
};
Module.cache = {};
function req(filename) {
  // 自己实现了一个require方法
  let current = Module.resolveFileName(filename);
  if (Module.cache[current]) {
    return Module.cache[current].exports;
  }
  let module = new Module(current); // 产生一个module
   Module.cache[current] = module;
  module.load();

  return module.exports; // 默认导出module.exports对象
}
let json = require("./a");
console.log(json);

// node中的模块 3类 文件模块  第三方模块(需要安装)  内置模块(fs)
// 模块的查找路径:
// 先找文件,找不到的话 找文件夹  

// 第三方模块查找
require('commander'); // 找不到会像上级查找node_module 直到根目录如果跟目录找不到则报错, 会先找main 对应的字段如果有直接查找,如果没有main 会找index.js / index.json

相关文章

网友评论

      本文标题:手动实现commonjs规范

      本文链接:https://www.haomeiwen.com/subject/lwzaectx.html