nodejs学习: require模拟实现

179 阅读1分钟

原生module对象

实例属性

/**
 * @file test.js
 * 
 */
console.log(this) // {}

// Module 构造函数的实例属性
console.log(module)
 Module {
  id: '.',
  path: '/Users/valar/study/nodejs',
  exports: {},
  parent: null,
  filename: '/Users/valar/study/nodejs/test.js',
  loaded: false,
  children: [],
  paths: [
    '/Users/valar/study/nodejs/node_modules',
    '/Users/valar/study/node_modules',
    '/Users/valar/node_modules',
    '/Users/node_modules',
    '/node_modules'
  ]
}

静态属性

// Module 构造函数的静态属性和方法
console.log(module.__proto__.constructor) 
  _cache: [Object: null prototype] {
    '/Users/valar/study/nodejs/test.js': Module {
      id: '.',
      path: '/Users/valar/study/nodejs',
      exports: {},
      parent: null,
      filename: '/Users/valar/study/nodejs/test.js',
      loaded: false,
      children: [],
      paths: [Array]
    }
  },
  _pathCache: [Object: null prototype] {
    '/Users/valar/study/nodejs/test.js\x00': '/Users/valar/study/nodejs/test.js'
  },
  _extensions: [Object: null prototype] {
    '.js': [Function (anonymous)],
    '.json': [Function (anonymous)],
    '.node': [Function (anonymous)]
  },
  globalPaths: [
    '/Users/valar/.node_modules',
    '/Users/valar/.node_libraries',
    '/Users/valar/.nvm/versions/node/v14.17.6/lib/node'
  ],
  _debug: [Function: deprecated],
  _findPath: [Function (anonymous)],
  _nodeModulePaths: [Function (anonymous)],
  _resolveLookupPaths: [Function (anonymous)],
  _load: [Function (anonymous)],
  _resolveFilename: [Function (anonymous)],
  createRequireFromPath: [Function: deprecated],
  createRequire: [Function: createRequire],
  _initPaths: [Function (anonymous)],
  _preloadModules: [Function (anonymous)],
  syncBuiltinESMExports: [Function: syncBuiltinESMExports],
  Module: [Circular *1],
  runMain: [Function: executeUserEntryPoint]
  
  // Module 构造函数的实例方法
  console.log(module.__proto__.constructor.prototype)
  {
  load: [Function (anonymous)],
  require: [Function (anonymous)],
  _compile: [Function (anonymous)]
}
  
const fs = require("fs");
const path = require("path");
const vm = require("vm");

function Module(id) {
  this.id = id; // 绝对路径
  this.exports = {};
}

Module._resolveFilename = function (filename) {
  const absPath = path.resolve(filename);

  // 判断当前路径对应的内容(目录|文件)是否存在
  if (fs.existsSync(absPath)) {
    return absPath;
  } else {
    let suffix = Object.keys(Module._extensions);
    for (let i = 0; i < suffix.length; i++) {
      const newPath = absPath + suffix[i];
      if (fs.existsSync(newPath)) {
        return newPath;
      }
    }
  }
  throw new Error(`${filename} is not exists`);
};

Module._extensions = {
  ".js"(module) {
    // 读取内容, 默认是buffer,指定utf-8
    let content = fs.readFileSync(module.id, "utf-8");

    // 包装为闭包函数
    content = Module.wrapper[0] + content + Module.wrapper[1];

    // vm
    let compiledFn = vm.runInThisContext(content);

    // 准备参数
    const exports = module.exports;
    const dirname = path.dirname(module.id);
    const filename = module.id;

    // 调用
    compiledFn.call(exports, exports, myRequire, module, filename, dirname);
  },
  ".json"(module) {
    // 读取内容, 默认是buffer,指定utf-8
    let content = fs.readFileSync(module.id, "utf-8");
    content = JSON.parse(content);
    module.exports = content;
  },
};

Module.wrapper = [
  "(function (exports,require,module,__filename,__dirname) {",
  "})",
];

Module._cache = {};

Module.prototype.load = function () {
  // 判断文件类型
  let extname = path.extname(this.id);

  // 传递this给静态方法
  Module._extensions[extname](this);
};

function myRequire(filename) {
  // 1. 获取绝对路径
  let mPath = Module._resolveFilename(filename);

  //2. 缓存优先
  let cacheModule = Module._cache[mPath];
  if (cacheModule) {
    return cacheModule.exports;
  }

  // 3. 创建空对象加载目标模块
  let module = new Module(mPath);

  // 4.缓存已加载过的模块
  Module._cache[mPath] = module;

  //5. 加载执行
  module.load();

  // 6. 返回
  return module.exports;
}

let obj = myRequire("a.json");
let obj2 = myRequire("a.json");
console.log(obj);