commonjs require原理

JuoJuo發表於2019-02-22
// let a = require('xxxx')
// 1.讀取給定路徑的檔案裡的內容,拿到字串
//    -- 可能給了字尾,直接讀
//    -- 可能沒有給字尾,沒有的話就按照順序 .js .json .node優先順序來載入檔案
// 2.拿到絕對路徑去快取裡查詢一下,是否有載入過
//    -- 有就直接return
//    -- 沒有建立這個模組,模組裡有個this.exports物件
// 3.放如快取
let path = require('path')
let fs = require('fs')
let vm = require('vm')

function Module(fullPath) {
    this.fullPath = fullPath;
    this.exports = {};
}

Module._extentions = ['.js', '.json', '.node'];
Module._cache = {};

Module._resovleFilename = function(relativePath){
    let p = path.resolve(__dirname, relativePath);
    let ext = path.extname(p);
    if (ext && Module._extentions[ext]) {
        // 寫的是全路徑
    } else {
        // 拼接
        for (let i = 0; i < Module._extentions.length; i++) {
            let fullPath = p + Module._extentions[i];
            try{
                fs.accessSync(fullPath);
                return fullPath
            }catch(e){
                console.log(e)
            }
        }
    }
}
Module.prototype.load = function(){
    // js加閉包,json直接當物件
    let ext = path.extname(this.fullPath)
    Module._extentions[ext](this);
}
Module.wrapper = ["(function(exports, module, require){" , "\n})"]
Module.wrap = function(script) {
    return Module.wrapper[0] + script +  Module.wrapper[1];
}
Module._extentions['.js'] = function(module){
    let codeText = fs.readFileSync(module.fullPath);
    let fnStr = Module.wrap(codeText)
    let fn = vm.runInThisContext(fnStr);
    fn.call(module.exports, module.exports, module, req)
}
Module._extentions['.json'] = function(module){
    let codeText = fs.readFileSync(module.fullPath);
    module.exports = JSON.parse(codeText)
}
function req(p) {
    // 搞出絕對路徑
    let fullPath = Module._resovleFilename(p);
    // 拿到絕對路徑去快取裡找
    if(Module._cache[fullPath]) {
      return Module._cache[fullPath];
    }
    // 沒有快取說明沒有載入過
    let module = new Module(fullPath);
    module.load();
    Module._cache[fullPath] = module.exports;
    return module.exports
}

let a = req('./a')
console.log(a);

a.name = 'jack'
let bb = req('./a')
console.log(bb)


/* ***********引用傳遞,原來的那個會被改掉哦************ */
let a = require('./a')
console.log(a);//{ name: 1, age: 2 }


a.name = 'jack'
let bb = require('./a')
console.log(bb)//{ name: 'jack', age: 2 }
複製程式碼

相關文章