本文共 4245 字,大约阅读时间需要 14 分钟。
既然没有,我们就手写一个吧,这里先普及下备用的基础知识,请往下看
let fs = require("fs");fs.accessSync("./x.js") //当前目录中没有该文件则会报错
let path = require("path");console.log(path.extname("./c.js"))
var vm = require('vm');var localVar = 'initial value';//在runInThisContext创建的沙箱环境中执行var vmResult = vm.runInThisContext('localVar = "vm";');console.log('vmResult: ', vmResult); //vmResult: vmconsole.log('localVar: ', localVar); //localVar: initial value//在eval中执行var evalResult = eval('localVar = "eval";');console.log('evalResult: ', evalResult); //evalResult: evalconsole.log('localVar: ', localVar); //localVar: eval
有了这些基础知识的储备,已经迫不及待的开始手写源代码了
let path = require('path');let fs = require('fs');let vm = require('vm');// 声明构造函数Modulefunction Module(filename){ this.loaded = false; //用于检测是否被缓存过 this.filename = filename; //文件的绝对路径 this.exports = {} //模块对应的导出结果}//存放模块的扩展名Module._extensions = ['.js','.json'];//检测是否有缓存Module._cache = {};//拼凑成闭包的数组Module.wrapper = ['(function(exports,require,module){','\r\n})'];
function req(path) { //自己实现require方法,实现加载模块 // 根据输入的路径 变出一个绝对路径 let filename = Module._resolveFilename(path); // 通过这个文件名创建一个模块 let module = new Module(filename); module.load(); //让这个模块进行加载 根据不同的后缀加载不同的内容 return module.exports}
//如果没写扩展名,我们给它默认添加扩展名Module._resolveFilename = function (p) { p = path.join(__dirname,p); if(!/\.\w+$/.test(p)){ //如果没写扩展名,尝试添加扩展名 for(let i=0;i
Module.prototype.load = function () { // 加载模块本身 js按照js加载 json按照json加载 let extname = path.extname(this.filename); //判断后缀名 Module._extensions[extname](this); //把module实例传过去}
Module._extensions['.json'] = function (module) { let content = fs.readFileSync(module.filename,'utf8'); module.exports = JSON.parse(content);};
写了这么多,我们先来测试下.json结尾的文件,有没有被写入到module.exports中
// 后缀名为js的加载方法Module._extensions['.js'] = function (module) { //取出加载模块的内容 let content = fs.readFileSync(module.filename,'utf8'); // 形成闭包 let script = Module.wrap(content); //让js代码执行 let fn = vm.runInThisContext(script); fn.call(module,module.exports,req,module)};7、我们来看下Module.wrap(content)如何进行代码解析的
Module.wrap = function(content){ return Module.wrapper[0] + content +Module.wrapper[1];};是不是很简单,只是简单的js字符串拼接成闭包的函数,然后让其进行执行。到目前为止,基本的功能已经实现了,我们先来测试下。但是我们还没实现缓存,接下来继续
//检测是否有缓存Module._cache = {};//改造下req方法function req(path) { //自己实现require方法,实现加载模块 // 根据输入的路径 变出一个绝对路径 let filename = Module._resolveFilename(path); if(Module._cache[filename]){ //有缓存直接取缓存中的 return Module._cache[filename].exports; } // 通过这个文件名创建一个模块 let module = new Module(filename); module.load(); //让这个模块进行加载 根据不同的后缀加载不同的内容 Module._cache[filename] = module; //第一次加载先缓存 return module.exports}
let path = require('path');let fs = require('fs');let vm = require('vm');// 声明构造函数Modulefunction Module(filename){ this.loaded = false; //用于检测是否被缓存过 this.filename = filename; //文件的绝对路径 this.exports = {} //模块对应的导出结果}//存放模块的扩展名Module._extensions = ['.js','.json'];//检测是否有缓存Module._cache = {};//拼凑成闭包的数组Module.wrapper = ['(function(exports,require,module){','\r\n})'];//如果没写扩展名,我们给它默认添加扩展名Module._resolveFilename = function (p) { p = path.join(__dirname,p); if(!/\.\w+$/.test(p)){ //如果没写扩展名,尝试添加扩展名 for(let i=0;i
原文发布时间为:2018年06月25日
原文作者:言sir
本文来源: 如需转载请联系原作者