How to get the real require function in Node.js, when using a bundler

Recently I wanted to create a JavaScript module that would use the zlib module in Node, and fallback on pako in browsers. Seems simple enough, but actually proved somewhat difficult. Browser bundlers rewrite the CommonJS require function and by default shim the Node built-in zlib module with a less-performant pseudo-asynchronous pure-JS implementation. So how can we accomplish this you ask?

We could side-step the code that rewrites the require function if we access the require function dynamically, but require isn’t a global variable (except in REPL), it’s local to each module. A nasty solution that might come to mind might be code evaluation, and in webpack that would actually work, but browserify uses the same name for the rewritten function. All just as well, nobody wants code evaluation in their code, especially if you want to use a Content Security Policy. Fortunately, with some knowledge of how CommonJS works, a nice solution is possible.

Node’s CommonJS wraps modules like this:

1
2
(function (exports, require, module, __filename, __dirname) { // Module code here
});

This means that in the top level of the module, we can use the arguments magic variable to access all of the CommonJS local module variables dynamically. From there, it’s a simple matter of finding the one we are look for and determining if that function is the real Node require or one provided by the bundler. Using typeof to find the function and checking for the resolve property will accomplish both of these things nicely.

Comments