覆盖require函数

Posted

技术标签:

【中文标题】覆盖require函数【英文标题】:Override the require function 【发布时间】:2015-03-12 22:52:18 【问题描述】:

是否可以覆盖 global require 函数,在process 级别影响它?

据我所知,require 函数在包装 NodeJS 脚本的函数中作为参数提供:

(function (..., require, __dirname)  // something like this
   // The wrapped code
)(...);

有没有办法修改require函数?

(function () 
    var _require = require;
    require = function () 
        console.log("...");
        _require.apply(this, arguments);
    ;
)();

这可能只会影响它所在的​​脚本。

我们如何在流程级别对其进行修改?

【问题讨论】:

看来 6to5 为其require hook 做了一些类似的事情。 您可以尝试在主文件中覆盖global.requireglobal.require = function(). 我很想知道为什么 @mscdex 我期待这个问题。 :-) 我稍后会告诉你。 不,节点中的要求是特定于模块的,这是不可能的。 【参考方案1】:

这是我找到的解决方法。如果有更好的解决方案,我愿意看到。

我创建了一个名为req-modifier.js的脚本:

module.exports = function (_args) 

    var _require = _args[1];
    function newRequire () 
        console.log("Require is called");
        return _require.apply(this, arguments);
              
    newRequire.__proto__ = _require;

    _args[1] = newRequire;
;  

然后从我要修改require函数的文件中,我做:

require("./req-modifier")(arguments);

var foo = require("./foo");

限制是我每次都必须调用req-modifier 函数。

【讨论】:

"限制是我每次都必须调用 req-modifier 函数。" - 这实际上意味着你必须从你希望能够做到这一点的每个模块中调用你自己的东西。根本不是真正的解决方案。【参考方案2】:
var Module = require('module');
var originalRequire = Module.prototype.require;

Module.prototype.require = function()
  //do your thing here
  return originalRequire.apply(this, arguments);
;

【讨论】:

完美运行。感谢这个 sn-p。 刚刚注意到您的回答。抱歉这么晚才标记这个答案!谢谢! 我可以知道我需要在哪里放置此代码以确保每次需要调用(打字稿)都会调用它吗?【参考方案3】:

mock-require 通过overriding Module._load 执行此操作(这就是real require actually calls)。

【讨论】:

我在一个简单的模块中抽象了这个,它提供了一个条件接口来覆盖模块解析逻辑(并能够重置原始模块解析逻辑)github.com/gajus/override-require【参考方案4】:

这是一个基于@orourkedd 的更安全的原生 ES6 答案,它在所有 require 调用上都充当事件侦听器,它可能看起来像是在替换 require,但如果你仔细观察,它实际上是在说:require = require 并捕获对它的调用但返回原始行为。这只是 Proxy() 的数百万次使用中的一种,这对我来说非常方便,例如在 Typescript 中将 tsconfig“路径”映射到真正的模块节点将解决。

我会说这不是“猴子补丁”,因为它在语言的较低级别。

var Module = require('module');
Module.prototype.require = new Proxy(Module.prototype.require,
    apply(target, thisArg, argumentsList)

        let name = argumentsList[0];

        /*do stuff to ANY module here*/

        if(/MyModule/g.test(name))
            /*do stuff to MY module*/
            name = "resolveAnotherName"
        

        return Reflect.apply(target, thisArg, argumentsList)
    
)

【讨论】:

哦,我忘了你也可以发布代理,所以这不是永久性的。 您正在使用代理这一事实并不影响它是猴子修补的事实(并不是说猴子修补一定不好)。 在你的回答中你说你用它使 tsconfig 的路径工作。你能分享你的代码吗?从过去 1 周开始,我一直在为 tsconfig 的路径而苦苦挣扎。这真的很有帮助。谢谢。

以上是关于覆盖require函数的主要内容,如果未能解决你的问题,请参考以下文章

覆盖 require.js 中的 setTimeout

setup.py & pip:从 requirements.txt 覆盖依赖项的子依赖项之一

如何在 Ruby 中分析 `require` 语句?

关于METINFO5.3漏洞引发的变量覆盖漏洞

如何使用 mongoosejs 用鉴别器覆盖父模式字段

Karma +Jasmine+ require JS进行单元测试并生成测试报告代码覆盖率报告