前言
这两天在学习nodejs相干的货色,在b站上看到一个up主分享的视频还挺不错的,于是跟着敲了一下。
实现
第一步:定义myRequire办法
function myRequire(filename) { // 获取绝对路径 const mPath = Module._resolveFilename(filename); // 缓存优先 const cacheModule = Module._cache[mPath]; if (cacheModule) return cacheModule.exports; // 创立空对象加载指标模块 const module = new Module(mPath); // 缓存已加载模块 Module._cache[mPath] = module; // 执行加载 module.load(); return module.exports;}
第二步:定义Module类办法
function Module(id) { // 模块id理论就是绝对路径 this.id = id; this.exports = {};}
第三步:实现Module._resolveFilename获取文件绝对路径的办法,只对以后的目录做了简略的查找、判断,理论会向上一层层查找模块,此处省略。当找不到时会尝试对文件名拼接文件后缀,此处只提供了js和json的办法,如果还是找不到便抛出谬误。
Module._resolveFilename = function (filename) { // 拼接当前目录和文件名 const mPath = path.join(__dirname, filename); // 判断此文件是否存在,存在之后返回 if (fs.existsSync(mPath)) { return mPath; } // 如果不存在,尝试拼接后缀 const suffixs = Object.keys(Module._extensions); for (let i = 0; i < suffixs.length; i++) { const _mPath = mPath + suffixs[i]; if (fs.existsSync(_mPath)) { return _mPath; } } // 找不到抛错 console.log(new Error(`${filename} is no exits`));};
第四步:当获取到文件的绝对路径后,先去缓存中查找模块,如果有间接返回。反之创立模块对象,并向缓存中增加此模块,最初执行模块加载,也是外围的编译执行模块。
模块加载依据不同的文件类型去执行对应的编译办法,此处只做了js和json的编译办法。
js文件读取内容之后,将js字符串封装成一个办法,并向其提供对应的模块可应用默认变量,最初应用vm.runInThisContext办法去运行js代码。
json文件就更简略了,间接读取文件应用JSON.parse格式化之后赋值给module.exports即可
Module._wrapeer = [ "(function(exports, module, require, __dirname, __filename){", "})",];Module._extensions = { ".js"(_module) { // 读取文件内容 const content = fs.readFileSync(this.id, "utf-8"); // 将内容字符串封装成一个函数,并传入exports、module、require、__dirname、__filename默认能够应用的变量 const contentFn = Module._wrapeer[0] + content + Module._wrapeer[1]; // 调用node.js自带的vm.runInThisContext办法运行字符串的js代码 const fn = vm.runInThisContext(contentFn); // 创立模块须要的默认变量 const exports = this.exports; const module = this; const dirname = path.dirname(this.id); const filename = this.id; // 执行模块 fn.call(exports, exports, module, myRequire, dirname, filename); }, ".json"(_module) { // JSON.parse格式化读取内容并设置给_module.exports即可 const content = JSON.parse(fs.readFileSync(_module.id, "utf-8")); _module.exports = content; },}Module.prototype.load = function () { // 依据文件类型去执行对应的编译办法 const extname = path.extname(this.id); Module._extensions[extname](this);};
最初,返回module.exports即是导出的内容。up主叫five爱前端,感兴趣的本人去搜吧。