具体实现步骤:

  1. 导入相关模块,创建一个Require方法。
  2. 抽离通过Module._load方法,用于加载模块。
  3. Module.resolveFilename 根据相对路径,转换成绝对路径。
  4. 缓存模块 Module._cache,同一个模块不要重复加载,提升性能。
  5. 创建模块 id: 保存的内容是 exports = {}相当于this。
  6. 利用tryModuleLoad(module, filename) 尝试加载模块。
  7. Module._extensions使用读取文件。
  8. Module.wrap: 把读取到的js包裹一个函数。
  9. 将拿到的字符串使用runInThisContext运行字符串。
  10. 让字符串执行并将this改编成exports。

    1. function Require(modulePath) {
    2. // 获取当前要加载的绝对路径
    3. let absPathname = path.resolve(__dirname, modulePath);
    4. // 获取所有后缀名
    5. const extNames = Object.keys(Module._extensions);
    6. let index = 0;
    7. // 存储原始文件路径
    8. const oldPath = absPathname;
    9. function findExt(absPathname) {
    10. if (index === extNames.length) {
    11. return throw new Error('文件不存在');
    12. }
    13. try {
    14. fs.accessSync(absPathname);
    15. return absPathname;
    16. } catch(e) {
    17. const ext = extNames[index++];
    18. findExt(oldPath + ext);
    19. }
    20. }
    21. // 递归追加后缀名,判断文件是否存在
    22. absPathname = findExt(absPathname);
    23. // 从缓存中读取,如果存在,直接返回结果
    24. if (Module._cache[absPathname]) {
    25. return Module._cache[absPathname].exports;
    26. }
    27. // 创建模块,新建Module实例
    28. const module = new Module(absPathname);
    29. // 添加缓存
    30. Module._cache[absPathname] = module;
    31. // 加载当前模块
    32. tryModuleLoad(module);
    33. // 返回exports对象
    34. return module.exports;
    35. }

    上述代码具体步骤:

  11. 获取模块的绝对路径和后缀名

  12. 递归追加后缀名,判断文件是否存在