CommonJs的require简易实现

71 阅读1分钟

实现

src/r.js

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

function r (filename) {
    // 获取绝对路径
    const absolutePath = path.resolve(__dirname, filename)
    // 先读取文件内容
    const content = fs.readFileSync(absolutePath, 'utf-8')
    // 把文件内容包裹到function里面,这就是为什么我们在写node.js模块内容的时候可以直接使用module, require, exports, _dirname, _filename
    const wrap = ['(function name(module, require, exports, _dirname, _filename) {',
        '})']
    // 最后的包裹结果
    const wrapped = wrap[0] + content + wrap[1]
    // 创建js可运行代码
    const vmJS = new vm.Script(wrapped)
    // 执行js,得到包裹的方法
    const fn = vmJS.runInThisContext()
    // 构建module
    const module = {
        exports: {}
    }
    // 执行函数并传入参数,模块里若使用到了require,此时就是传入的r,递归导入
    fn(module, r, module.exports, __dirname, absolutePath)
    // 返回导出内容
    return module.exports
}
module.exports = r

测试

src/index.js

const r = require('./r') // 这里的require还是node.js里的
const { test, fn } = r('mock.js')
test()
fn()

src/mock.js

const { fn } = require('../public/index.js')
function test () {
    console.log(Array.from(arguments))
}
module.exports = {
    test,
    fn
}

public/index.js

module.exports.fn = function() {
    return 111
}