35

Is it possible to override the global require function, affecting it at process level?

From what I know, the require function is provided as argument in the function that wraps the NodeJS scripts:

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

Is there any way to modify the require function?

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

This will probably affect only the script where it's located.

How can we modify it at the process level?

Ionică Bizău
  • 109,027
  • 88
  • 289
  • 474

4 Answers4

89
var Module = require('module');
var originalRequire = Module.prototype.require;

Module.prototype.require = function(){
  //do your thing here
  return originalRequire.apply(this, arguments);
};
orourkedd
  • 6,201
  • 5
  • 43
  • 66
11

mock-require does this by overriding Module._load (which is what the real require actually calls).

josh3736
  • 139,160
  • 33
  • 216
  • 263
  • I have abstracted this in a simple module that provides a conditional interface to override module resolution logic (and enables to reset the original module resolution logic) https://github.com/gajus/override-require – Gajus Sep 10 '16 at 20:37
11

Here is a much safer native ES6 answer based on @orourkedd which acts like an event listener on all require calls, It might look like its replacing require but if you look closer its actually saying: require = require and trap calls to it but return original behaviour. This is just one of the millions of uses of Proxy() which has been really handy for me, for example in Typescript for mapping tsconfig "paths" with the real module node will resolve.

I would go as far as to say that this is not "Monkey patching" as its on a lower level of the language.

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)
    }
})
  • Oh I forgot you can release proxies too so this is not permanent. – Adam Miles Crockett Mar 07 '17 at 12:21
  • The fact that you're using Proxy doesn't affect the fact that it's monkey patching (not that monkey patching here is necessarily bad). – andrezsanchez May 21 '18 at 17:50
  • In your answer you said you used it make tsconfig's paths work. Can you please share your code for that? I've been struggling with tsconfig's paths from last 1 week. It would really help. Thanks. – TheWhiteFang Aug 16 '21 at 13:46
1

This is the workaround I found. If there is any better solution, I'm open to see it.

I created a script named 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;
};  

Then from the files I want to modify the require function, I do:

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

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

The limitation is that I have to call every time the req-modifier function.

Ionică Bizău
  • 109,027
  • 88
  • 289
  • 474
  • 1
    "The limitation is that I have to call every time the req-modifier function." - that practically means you have to call your own thing from every module you'd like to be able to do this. Not really a solution at all. – Benjamin Gruenbaum Jan 14 '15 at 17:40