Node 引入模塊過程

調用 require 方法引入模塊

調用的是模塊原型上的方法, 當前文件在解析過程當中已經成了模塊對象json

// 模塊類
function Module() { }

Module.prototype.require = function(id) {
  // 返回模塊加載內容
  return Module._load(id, this, false)
}

function myRequire(filePath) {
  // 其實是 mod.require('./test') , mod是當前文件模塊,
  return Module.prototype.require(filePath)
}
let r = myRequire('./test')
複製代碼

調用 Module._load(request, parent, isMain) 方法加載模塊

// 不一樣擴展名文件處理策略
Module._extensions = {
  '.js': function() {},
  '.json': function() {}
}
// 簡化版 _resolveFilename 方法(無需細究)
Module._resolveFilename = function(require) {
  const filePath = path.resolve(__dirname, require)
  const exists = fs.existsSync(filePath)
  if (exists) {
    return filePath
  }

  let keys = Object.keys(Module._extensions)
  for (let i = 0; i < keys.length; i++) {
    const currentPath = filePath + keys[i]
    if (fs.existsSync(currentPath)) {
      return currentPath
    }
  }
}

Module._load = function(request, parent, isMain) {
  // 解析絕對路徑
  const fileName = Module._resolveFilename(request, parent, isMain)
  // return module.exports
}
複製代碼

建立模塊對象

function Module(id = '', parent) {
  this.id = id
  // 父級路徑
  this.path = path.dirname(id)
  this.exports = {}
  this.parent = parent
  this.filename = null
  this.loaded = false
  this.children = []
}

Module._load = function(request, parent, isMain) {
  // 解析絕對路徑
  const fileName = Module._resolveFilename(request, parent, isMain)
  // 建立新的模塊對象
  const module = new Module(fileName, parent)
  return module.exports
}
複製代碼

調用模塊原型上的加載方法 load

Module.prototype.load = function(fileName) {

}

Module._load = function(request, parent, isMain) {
  // 解析絕對路徑
  const fileName = Module._resolveFilename(request, parent, isMain)
  const module = new Module(fileName, parent)
  // 將文件內容載入模塊對象
  module.load(fileName)
  return module.exports
}
複製代碼

獲取文件擴展名

Module.prototype.load = function(fileName) {
  // const extension = findLongestRegisteredExtension(filename);
  const extension = path.extname(fileName)
}
複製代碼

根據擴展名調用對應加載策略進行加載

Module._extensions = {
  '.js': function() {

  },
  '.json': function() {

  }
}

Module.prototype.load = function(fileName) {
  // const extension = findLongestRegisteredExtension(filename);
  const extension = path.extname(fileName)
  Module._extensions[extension](this, fileName)
}
複製代碼

各類文件加載策略

json

Module._extensions = {
  '.js': function() {},
  '.json': function(module, filename) {
    // 讀取文件內容 - 字符串
    const content = fs.readFileSync(filename, 'utf8');

    // 轉化爲對象賦值到 module.exports 上
    module.exports = JSON.parse(content)
  }
}
複製代碼

js

Module.warp = function(script) {
  let arr = [
    '(function(exports, require, module, __filename, __dirname) {',
    script,
    '})'
  ]
  return arr.join('')
}

Module._extensions = {
  '.js': function(module, filename) {
    // 讀取文件內容 - 字符串
    const content = fs.readFileSync(filename, 'utf8')
    // 調用包裝方法將字符串包裝成函數字符串
    const wrapper = Module.warp(content)
    const compiledWrapper = vm.runInThisContext(wrapper)
    // 準備要傳入的參數
    const exports = module.exports
    const thisValue = exports
    const require = myRequire
    const dirname = path.dirname(filename)
    // 執行函數返回結果
    compiledWrapper.call(thisValue, exports, require, module, filename, dirname)
  },
  '.json': function(module, filename) { }
}
複製代碼

模塊緩存實現

Module._cache = {}

Module._load = function(request, parent, isMain) {
  // 解析絕對路徑
  const fileName = Module._resolveFilename(request, parent, isMain)

  // 查找是否有模塊緩存
  const cachedModule = Module._cache[fileName]
  if (cachedModule !== undefined) {
    // 返回緩存內容
    return cachedModule.exports
  }

  const module = new Module(fileName, parent)
  // 將模塊置入緩存
  Module._cache[fileName] = module

  module.load(fileName)
  return module.exports
}
複製代碼

完整代碼

const path = require('path')
const fs = require('fs')
const vm = require('vm')


function Module(id = '', parent) {
  this.id = id
  // 父級路徑 ..
  this.path = path.dirname(id)
  this.exports = {}
  this.parent = parent
  this.filename = null
  this.loaded = false
  this.children = []
}

function myRequire(filePath) {
  return Module.prototype.require(filePath)
}

Module.warp = function(script) {
  let arr = [
    '(function(exports, require, module, __filename, __dirname) {',
    script,
    '})'
  ]
  return arr.join('')
}

Module._extensions = {
  '.js': function(module, filename) {
    // 讀取文件內容 - 字符串
    const content = fs.readFileSync(filename, 'utf8')
    // 調用包裝方法將字符串包裝成函數字符串
    const wrapper = Module.warp(content)
    const compiledWrapper = vm.runInThisContext(wrapper)
    // 準備要傳入的參數
    const exports = module.exports
    const thisValue = exports
    const require = myRequire
    const dirname = path.dirname(filename)
    // 執行函數返回結果
    compiledWrapper.call(thisValue, exports, require, module, filename, dirname)
  },
  '.json': function(module, filename) {
    // 讀取文件內容 - 字符串
    const content = fs.readFileSync(filename, 'utf8')

    // 轉化爲對象賦值到 module.exports 上
    module.exports = JSON.parse(content)
  }
}

Module._resolveFilename = function(require) {
  const filePath = path.resolve(__dirname, require)
  const exists = fs.existsSync(filePath)
  if (exists) {
    return filePath
  }

  let keys = Object.keys(Module._extensions)
  for (let i = 0; i < keys.length; i++) {
    const currentPath = filePath + keys[i]
    if (fs.existsSync(currentPath)) {
      return currentPath
    }
  }
}

Module.prototype.load = function(fileName) {
  // const extension = findLongestRegisteredExtension(filename);
  const extension = path.extname(fileName)
  Module._extensions[extension](this, fileName)
}

Module._cache = {}

Module._load = function(request, parent, isMain) {
  // 解析絕對路徑
  const fileName = Module._resolveFilename(request, parent, isMain)

  // 查找是否有模塊緩存
  const cachedModule = Module._cache[fileName]
  if (cachedModule !== undefined) {
    // 返回緩存內容
    return cachedModule.exports
  }

  const module = new Module(fileName, parent)
  // 將模塊置入緩存
  Module._cache[fileName] = module

  module.load(fileName)
  return module.exports
}

Module.prototype.require = function(id) {
  return Module._load(id, this, false)
}

let r = myRequire('./test.js')
myRequire('./test.js')
myRequire('./test.js')
console.log(r)
複製代碼
相關文章
相關標籤/搜索