看穿node中的Module

为了减小变量污染以及代码维护node采用了CommonJS规范。今天模拟一下Module。node

  1. 首先建立被引入文件 a.js
module.exports = 'hello';
复制代码
  1. 建立Module文件
//定义Module类
class Module{
    constructor(filename){
        this.filename = filename;
        this.exports = {};
    }
}
//定义require方法
function myRequire(){
    
}
let resut = myRequire('./a');
复制代码
  1. 获取文件路径
function myRequire(filename){
    //获取文件绝对路径
    filename = Module.getPath(filename);
}
class Module{
    ...
    //Module下定义静态方法
    static getPath(filename){
        filename = path.join(__dirname,filename);
        let ext = path.extname(filename);
        let pathName = '';
        let error = filename + " is not exist";
        //判断文件是否存在拓展名
        if(ext){
            try{
                fs.accessSync(filename);
                return filename;
            }catch(e){
                throw error;
            }
        }

        for(var i=0; i<Module.extentions.length; i++){
        //给文件加上拓展名,查找文件是否存在
            pathName = filename + Module.extentions[i];
            try{
                fs.accessSync(pathName);
                return pathName;
            }catch(e){}
        }
        throw error;
    }
}
//定义拓展名
Module.extentions = ['.js','.json','.node'];
复制代码
  1. 读取文件
class Module{
    ...
     load(){
        let ext = path.extname(this.filename).slice(1);
        //根据文件类型读取文件
        Module.extentions[ext](this);
    }
    static wrap(script){
        return Module.warper[0] + script + Module.warper[1];
    }
}
Module.extentions["js"] = function(module){
    let script = fs.readFileSync(module.filename,'utf8');
    let fnStr = Module.wrap(script);
    //(function(exports,require,module,__dirname,__filename){module.exports = 'hello'})
    
    let dirname = path.resolve(module.filename,'../');
    vm.runInThisContext(fnStr).call(module.exports,module.exports,myRequire,module,dirname,module.filename);
    //文件内部会得到传过来的module对象
    //模块内部将要导出的文件挂载到module.exports上
    //module.exports = 'hello'
}
Module.extentions["json"] = function(module){
    let script = fs.readFileSync(module.filename,'utf8');
    module.exports = JSON.parse(script);
}
//用于拼接嵌套js文件
Module.warper = ["(function(exports,require,module,__dirname,__filename){",    "\n})"];
function myRequire(filename){
    ...
    let module = new Module(filename);
    module.load();
}
复制代码
  1. 暂存已读取文件
function myRequire(filename){
    let fileCache = Module.caches[filename];
    //有缓存读取缓存
    if(fileCache){
        return fileCache.exports;
    }
    //加载文件
    let module = new Module(filename);
    module.load();
    //缓存文件
    Module.caches[filename] = module;
}
复制代码
  1. 完整代码

a.jsjson

module.exports = 'hello'
复制代码

module.js缓存

let path = require('path');
let fs = require('fs');
let vm = require('vm');


class Module{
    constructor(filename){
        this.filename = filename;
        this.exports = {};
    }
    load(){
        let ext = path.extname(this.filename).slice(1);
        Module.extentions[ext](this);
    }
    static wrap(script){
        return Module.warper[0] + script + Module.warper[1];
    }
    static getPath(filename){
        filename = path.join(__dirname,filename);
        let ext = path.extname(filename);
        let pathName = '';
        let error = filename + " is not exist";
        if(ext){
            try{
                fs.accessSync(filename);
                return filename;
            }catch(e){
                throw error;
            }
        }

        for(var i=0; i<Module.extentions.length; i++){
            pathName = filename + Module.extentions[i];
            try{
                fs.accessSync(pathName);
                return pathName;
            }catch(e){}
        }
        throw error;
        // path.resolve(__dirname, filename);
    }
}
Module.extentions = ['.js','.json','.node'];
Module.caches = {};
Module.warper = ["(function(exports,require,module,__dirname,__filename){",    "\n})"];
Module.extentions["js"] = function(module){
    let script = fs.readFileSync(module.filename,'utf8');
    let fnStr = Module.wrap(script);
    let dirname = path.resolve(module.filename,'../');
    vm.runInThisContext(fnStr).call(module.exports,module.exports,myRequire,module,dirname,module.filename);
}
Module.extentions["json"] = function(module){
    let script = fs.readFileSync(module.filename,'utf8');
    module.exports = script;
}

function myRequire(filename){
    //查找文件绝对路径
    filename = Module.getPath(filename);
    let fileCache = Module.caches[filename];
    if(fileCache){
        return fileCache.exports;
    }
    //加载文件
    let module = new Module(filename);
    module.load();
    Module.caches[filename] = module;
    return module.exports;
}

let school = myRequire('./a.js');

复制代码

欢迎你们指出问题提出看法!bash

相关文章
相关标签/搜索