Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why we need to pass module.exports as a parameter since we are already passing module as a parameter?

I have been going through some online tutorials on Node.js. What I understood is that, on using require(./file-path) function, the node gets the content of that file and wraps inside an immediately invoking function

(function(exports, require, module, __filename, __dirname) {
  // content 
}())

I understood the difference between exports and module.exports. That's all I can see in the internet on searching the above question. But what my question is , why we need to pass module.exports and module to the wrapping IIFE? We could have passed module alone and then get module.exports from it. Is there any advantage on doing like this? Normally when we pass an object to a function , we don't have to pass object.property additionally.

like image 837
MELWIN VINCENT Avatar asked Aug 01 '17 13:08

MELWIN VINCENT


2 Answers

The answer is: historical reasons.

You're right, we could have only module and exports would not be needed but it's still there for backwards compatibility.

It used to be a time when the module wrapper was changed in pretty much every patch release.

In Node 0.1.11 the module wrapper was:

var wrapper = "function (__filename) { "+
              "  var onLoad; "+
              "  var onExit; "+
              "  var exports = this; "+
              content+
              "\n"+
              "  this.__onLoad = onLoad;\n"+
              "  this.__onExit = onExit;\n"+
              "};\n";

See: https://github.com/nodejs/node/blob/v0.1.11/src/node.js#L167#L177

As you can see the exports was the same as the this that the wrapper function was called with. You couldn't swap it with a new object and you couldn't even add some reserved keys to it - e.g. you couldn't safely export a property named __onExit.

Then in 0.1.12 it was:

var wrapper = "function (__filename, exports) { " + content + "\n};";

See: https://github.com/nodejs/node/blob/v0.1.12/src/node.js#L243-L245

Here the exports was an object supplied as one of the arguments but you couldn't swap it with a new object, you could only add or remove properties from the object that you got.

Then the 0.1.13 was the first to have this, i.e. require and include:

var wrapper = "function (__filename, exports, require, include) { " + content + "\n};";

See: https://github.com/nodejs/node/blob/v0.1.13/src/node.js#L225-L227

Then 0.1.14 was the first to have __module (with underscores) in the wrapper (and that dropped include):

var wrapper = "var __wrap__ = function (__module, __filename, exports, require) { " 
            + content 
            + "\n}; __wrap__;";

See: https://github.com/nodejs/node/blob/v0.1.14/src/node.js#L280-L284

And the 0.1.16 was the first to have a module argument (with no underscores) in the wrapper:

var wrapper = "var __wrap__ = function (exports, require, module, __filename) { " 
            + content 
            + "\n}; __wrap__;";

See: https://github.com/nodejs/node/blob/v0.1.16/src/node.js#L444-L448

It's been changed many times after that but this is the time that the module got introduced making the exports not necessary any more but still a useful shortcut, allowing you to use:

exports.a = 1;
exports.b = 2;
exports.c = 3;

instead of:

module.exports.a = 1;
module.exports.b = 2;
module.exports.c = 3;

though in practice if there was no exports then one would usually write:

const exports = module.exports;
exports.a = 1;
exports.b = 2;
exports.c = 3;

or more likely:

module.exports = {
  a: 1,
  b: 2,
  c: 3,
};

or, to have some checks in static analysis tools:

const a = 1;
const b = 2;
const c = 3;
module.exports = { a, b, c };

There are many ways to do it, it's a pretty flexible mechanism.

like image 90
rsp Avatar answered Nov 03 '22 00:11

rsp


Originally it was only exports and require. Later on, module was added in a backwards-compatible manner, to allow (among other things) overriding the exports object completely.

like image 26
OrangeDog Avatar answered Nov 03 '22 00:11

OrangeDog