具体实现步骤:
- 导入相关模块,创建一个Require方法。
- 抽离通过Module._load方法,用于加载模块。
- Module.resolveFilename 根据相对路径,转换成绝对路径。
- 缓存模块 Module._cache,同一个模块不要重复加载,提升性能。
- 创建模块 id: 保存的内容是 exports = {}相当于this。
- 利用tryModuleLoad(module, filename) 尝试加载模块。
- Module._extensions使用读取文件。
- Module.wrap: 把读取到的js包裹一个函数。
- 将拿到的字符串使用runInThisContext运行字符串。
让字符串执行并将this改编成exports。
function Require(modulePath) {// 获取当前要加载的绝对路径let absPathname = path.resolve(__dirname, modulePath);// 获取所有后缀名const extNames = Object.keys(Module._extensions);let index = 0;// 存储原始文件路径const oldPath = absPathname;function findExt(absPathname) {if (index === extNames.length) {return throw new Error('文件不存在');}try {fs.accessSync(absPathname);return absPathname;} catch(e) {const ext = extNames[index++];findExt(oldPath + ext);}}// 递归追加后缀名,判断文件是否存在absPathname = findExt(absPathname);// 从缓存中读取,如果存在,直接返回结果if (Module._cache[absPathname]) {return Module._cache[absPathname].exports;}// 创建模块,新建Module实例const module = new Module(absPathname);// 添加缓存Module._cache[absPathname] = module;// 加载当前模块tryModuleLoad(module);// 返回exports对象return module.exports;}
上述代码具体步骤:
获取模块的绝对路径和后缀名
- 递归追加后缀名,判断文件是否存在
