1.首先,使用和定义模块
定义
module.exports = function (){
// todos
}
使用
var myfunction = require('./xxx')
复制代码
2.CMD 模块化的实现
- 首先nodejs 全局定义了module
- require()方法的具体实现是nodejs中的"Module"来具体实现的(这个Module只是个定义,和node全局module无关)
- require简单实现逻辑
function require(path){
// 解析路径读取文件
var fileStr = fs.readFile(path);
// 加入到闭包中
var codeStr = "(function(module,exports){ +fileStr+ }) "
// 使用vm 得到可执行的fn
var fn = vm.runInThisContext(codeStr)
// 运行fn,让当前文件的module.exports 挂上相关的数据,此处是方法
fn.call(module,module,module.exports); // 得到module.export = function (){//todos}
// 导出module.exports就ok
return module.exports
}
复制代码
注意事项,里面只是简化版,理解流程
具体还需要加入.json||.js 判断,加入读取文件缓存等
3.commonjs 模块化更加精细实现
let path = require('path')
let fs = require('fs')
let vm = require('vm')
function Module(filename) {
this.loaded = false
this.filename = filename // 文件的绝对路径
this.exports = {} // 模块对应的导出结果
}
Module._extensions = ['.js', '.json']
Module._resolveFilename = function(p) {
p = path.join(__dirname, p) // c://xx/a
if (!/\.\w+$/.test(p)) {
// 尝试添加扩展名
for (let i = 0; i < Module._extensions.length; i++) {
let filePath = p + Module._extensions[i] // 拼出一个路径
// 判断文件是否存在
try {
fs.accessSync(filePath)
return filePath
} catch (e) {
if (i >= Module._extensions.length) {
throw new Error('module not Found')
}
}
}
} else {
return p
}
}
Module._cache = {}
// 如果后缀是.js
Module._extensions['.json'] = function(module) {
let content = fs.readFileSync(module.filename, 'utf8')
module.exports = JSON.parse(content)
}
Module.wrapper = ['(function (exports,require,module){', '\r\n})']
Module.wrap = function(content) {
return Module.wrapper[0] + content + Module.wrapper[1]
}
// 如果后缀是.js
Module._extensions['.js'] = function(module) {
let content = fs.readFileSync(module.filename, 'utf8')
let script = Module.wrap(content)
let fn = vm.runInThisContext(script)
fn.call(module.exports, module.exports, req, module)
}
Module.prototype.load = function() {
// 加载模块本身 js按照js加载 json按照json加载
let extname = path.extname(this.filename)
Module._extensions[extname](this)
}
function req(path) {
// 自己实现的require方法 可以加载模块
// 先要根据路径 变出一个绝对路径
let filename = Module._resolveFilename(path)
// 文件路径 (绝对路径) 唯一
if (Module._cache[filename]) {
// 如果加载过直接把加载的结果返回即可
// 有缓存把exports属性导出即可
return Module._cache[filename].exports
}
// 通过这个文件名创建一个模块
let module = new Module(filename)
module.load() // 让这个模块进行加载 根据不同的后缀加载不同的内容
Module._cache[filename] = module // 进行模块的缓存
// 返回最后的结果
return module.exports
}
复制代码