思路就是: 根据路径读取文件, 创建一个module实例, 判断文件类型是js还是json, json直接的话直接赋值给module的exports, js的话需要执行一下文件(利用eval或者vm.runInThisContext), 执行js需要修改this指向为module.exports,还要把module.exports传进去,用于赋值,这样才能让js模块里写的exports = xxx生效,成为引入模块的exports,
大体就这些流程,写的比较粗糙,不是教程,只用于个人记录回看,详细的讲解请移步更优质文章。
以下是代码
`const path = require('path') const fs = require('fs') const vm = require('vm')
class MyModule{ constructor(filePath){ this.id = filePath this.exports = {} } }
MyModule._cache = {} MyModule.loadModule = { js(module){ const res = fs.readFileSync(module.id, {encoding:'utf8'}) let str_js = '(function(exports,MyRequire){' + res + ' })' let fn = vm.runInThisContext(str_js) fn.call(module.exports,module.exports) }, json(module){ const res = fs.readFileSync(module.id) const file = JSON.parse(res) module.exports = file } }
function MyReqeuire(filePath){ let abs_path = path.join(__dirname,filePath) //有缓存则取用缓存的exports if (MyModule._cache[abs_path]) { return MyModule._cache[abs_path].exports } //没有缓存则新建一个模块实例,并缓存起来 const module = new MyModule(abs_path) MyModule._cache[abs_path] = module //根据文件类型选择不同方法进行加载模块 let type = path.extname(abs_path).slice(1) MyModule.loadModuletype return module.exports }
let ajson = MyReqeuire('./a.json') console.log(ajson); let bjs = MyReqeuire('./b.js') console.log(bjs); bjs.say()`