手写require 来理解node中的require引入过程

142 阅读1分钟

- node中require引入模块的过程

// require-mod.js

console.log("require", require.toString());

const { Module } = require("module");

// console.log("Module require", Module.prototype.require.toString());

// console.log("Module._load", Module._load.toString());

// console.log("module.load", module.load.toString());

// console.log("Module._extensions", Module._extensions[".js"].toString());

// console.log("module._compile", module._compile.toString());

现在就可以开启 nodemon require-mod.js 去看下代码实现了

- require手写代码

const { existsSync, readFileSync } = require("node:fs");
const vm = require("node:vm");
const { extname, dirname, resolve } = require("node:path");

const wrap = (content) => {
    return (
        "(function(exports,require,module,__filename,__dirname,){ " + content + "})"
    );
};

const safeWrap = (filename, content, mod) => {
    return vm.runInThisContext(content, {
            filename,
    });
};

const makeRequireFunction = (mod, redirects) => {
    let require;
    if (redirects) {
            // todo
    } else {
        require = (path) => {
            return mod.require(path);
        };
    }

    const resolve = () => {};
    require.resolve = resolve;
    
    const paths = () => {};
    require.paths = paths;

    require.extensions = Module._extensions;
    require.cache = Module._cache;

    return require;
};

class Module {
    constructor() {
        this.id = "";
        this.exports = {};
    }

    static _cache = {};

    static _extensions = {
        [".js"](mod) {
                const content = readFileSync(mod.id, "utf-8");
                mod._compile(content, mod.id);
        },
        [".json"](mod) {
                // todo
        },
        [".node"](mod) {
                // todo
        },
    };

    static _load(filePath) {
        const abFilePath = resolve(dirname(filePath), filePath);

        const modCache = Module._cache[abFilePath];
        if (modCache) return modCache.exports;

        if (!existsSync(abFilePath)) return;

        const mod = new Module(abFilePath);
        mod.id = abFilePath;
        mod.load(abFilePath);

        Module._cache[abFilePath] = mod;

        return mod.exports;
    }

    load(filePath) {
        const extName = extname(filePath);
        Module._extensions[extName](this);
        this.loaded = true;
    }

    _compile(content, filename) {
        const wrapperContent = wrap(content);
        const compiledWrapper = safeWrap(filename, wrapperContent);

        const exports = this.exports;
        const dirName = dirname(filename);

        const require = makeRequireFunction(this);

        compiledWrapper.call(this, exports, require, this, filename, dirName);
    }
}

const requireNew = (filePath) => {
    return Module._load(filePath);
};

const aaa = requireNew("./mmm.js");

console.log("aaa666666", aaa);

console.log("requireNew", module.require.toString());