看穿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

相關文章
相關標籤/搜索