NodeJS实现require模块

根据require模块实现流程步骤自实现require模块

NodeJS-require模块系统实现流程

  • 内部实现了一个require方法

    function require(path) {
        return self.require(path);
    }
  • 通过Module对象的静态__load方法加载模块文件

    Module.prototype.require = function(path) {
        return Module._load(path, this, /* isMain */ false);
    };
  • 通过Module对象的静态_resolveFilename方法,得到绝对路径并添加后缀名

    var filename = Module._resolveFilename(request, parent, isMain);
  • 根据路径判断是否存在缓存,若不存在则创建一个新的Module对象并缓存起来

    var cachedModule = Module._cache[filename];
    if (cachedModule) {
        return cachedModule.exports;
    }
    var module = new Module(filename, parent);
    Module._cache[filename] = module;
    // id是绝对路径
    function Module(id, parent) {
        this.id = id;
        this.exports = {};
    }
  • 利用tryModuleLoad方法加载模块

    tryModuleLoad(module, filename);
    • 取出模块后缀

      var extension = path.extname(filename);
    • 根据不同后缀查找不同方法并执行对应的方法,加载模块

      Module._extensions[extension](this, filename);
    • 是JSON就转换成对象

      module.exports = JSON.parse(internalModule.stripBOM(content));
    • 是JS就包裹一个函数

      var wrapper = Module.wrap(content);
      NativeModule.wrap = function(script) {
          return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
      };
      NativeModule.wrapper = ['(function (exports, require, module, __filename, __dirname) { ','\n});'];
    • 执行包裹函数之后的代码,拿到执行结果(String -- Function)

      var compiledWrapper = vm.runInThisContext(wrapper);
    • 利用call执行fn函数,修改module.exports的值

      var args = [this.exports, require, module, filename, dirname];
      var result = compiledWrapper.call(this.exports, args);
  • 返回module.exports

    return module.exports;

  • 接下来自实现require模块
  • 1.js:console.log(123);
  • Nhwrequire.js:

    const path = require("path");
    const fs = require("fs");
    const vm = require("vm");
    
    class NJModule {
        constructor(id) {
            this.id = id; // 保存当前模块的绝对路径
            this.exports = {};
        }
    }
    
    // 保存新的Module对象
    NJModule._cache = {};
    NJModule.wrapper = ['(function (exports, require, module, __filename, __dirname) { ', '\n});'];
    NJModule._extensions = {
        ".json": function (module) {
            let json = fs.readFileSync(module.id);
            //将JSON转换成对象,存入exports中
            let obj = JSON.parse(json);
            module.exports = obj;
        },
        ".js": function (module) {
            //根据文件路径读取文件数据
            let script = fs.readFileSync(module.id);
            //包裹成类型为字符串的函数
            let wrapper = NJModule.wrapper[0] + script + NJModule.wrapper[1];
            //执行包裹函数之后的代码,拿到执行结果(String -- Function)
            let compiledWrapper = vm.runInThisContext(wrapper);
            //利用call执行fn函数
            compiledWrapper.call(module.exports, module.exports);
        }
    };
    
    function NhwRequire(filePath) {
        //1.将传入的相对路径转换成绝对路径
        let absPath = path.join(__dirname, filePath);
        //2.根据路径判断是否存在缓存,若不存在则创建一个新的Module对象并缓存起来
        let cachedModule = NJModule._cache[absPath];
        if (cachedModule) {
            return cachedModule.exports;
        }
        let module = new NJModule(absPath);
        NJModule._cache[absPath] = module;
        //3.利用tryModuleLoad方法加载模块
        tryModuleLoad(module);
        //4.返回module.exports
        return module.exports;
    }
    
    function tryModuleLoad(module) {
        //1.取出模块后缀
        let extName = path.extname(module.id);
        //2.根据不同后缀查找不同方法并执行对应的方法,加载模块
        NJModule._extensions[extName](module);
    }
    
    let aModule = NhwRequire("./1.js");
    // console.log(aModule);

最后修改:2021 年 03 月 20 日 01 : 53 AM
如果觉得我的文章对你有用,请随意赞赏!