57

Looking at a random source file of the express framework for NodeJS, there are two lines of the code that I do not understand (these lines of code are typical of almost all NodeJS files).

/**
 * Expose `Router` constructor.
 */

exports = module.exports = Router;

and

/**
 * Expose HTTP methods.
 */

var methods = exports.methods = require('./methods');

I understand that the first piece of code allows the rest of the functions in the file to be exposed to the NodeJS app, but I don't understand exactly how it works, or what the code in the line means.

What do exports and module.exports actually mean?

I believe the 2nd piece of code allows the functions in the file to access methods, but again, how exactly does it do this.

Basically, what are these magic words: module and exports?

nbro
  • 15,395
  • 32
  • 113
  • 196
mrwooster
  • 23,789
  • 12
  • 38
  • 48

5 Answers5

80

To be more specific:

module is the global scope variable inside a file.

So if you call require("foo") then :

// foo.js
console.log(this === module); // true

It acts in the same way that window acts in the browser.

There is also another global object called global which you can write and read from in any file you want, but that involves mutating global scope and this is EVIL

exports is a variable that lives on module.exports. It's basically what you export when a file is required.

// foo.js
module.exports = 42;

// main.js
console.log(require("foo") === 42); // true

There is a minor problem with exports on it's own. The _global scope context+ and module are not the same. (In the browser the global scope context and window are the same).

// foo.js
var exports = {}; // creates a new local variable called exports, and conflicts with

// living on module.exports
exports = {}; // does the same as above
module.exports = {}; // just works because its the "correct" exports

// bar.js
exports.foo = 42; // this does not create a new exports variable so it just works

Read more about exports

Community
  • 1
  • 1
Raynos
  • 166,823
  • 56
  • 351
  • 396
  • Any chance you can explain why the exports = module.exports = Router; construct is used? – Shane Courtrille Feb 02 '12 at 20:11
  • That's unfortunate because most of the source I've seen so far (which I'll admit is pretty limited) uses it including connect.js – Shane Courtrille Feb 02 '12 at 21:38
  • @ShaneCourtrille he appears to want to set `module.exports` to `Router` and then wants to add properties to `exports` instead of `Router` so that's why he does all three. I would call that a silly coding style since he could just add properties to `Router` directly instead. – Raynos Feb 03 '12 at 08:11
  • I can't believe I've been using Node.JS for this long now and have been thinking the global object was `process` rather than `module`. +1 – Cory Gross Oct 02 '13 at 18:42
  • 1
    @ShaneCourtrille this answer explains why in more detail: http://stackoverflow.com/a/17944431/404699 – steampowered May 22 '15 at 12:21
  • I'm seeing different behavior to your `console.log(this === module); // true`? In my tests, Node.js / webpack / browserify set `this` inside require-ed module to be the same as `exports` rather than `module`. – Jokester Jan 06 '17 at 09:19
34

To expand on Raynos's answer...

exports is basically an alias for module.exports - I recommend just not using it. You can expose methods and properties from a module by setting them on module.exports, as follows:

//file 'module1.js'
module.exports.foo = function () { return 'bar' }
module.exports.baz = 5

Then you get access to it in your code:

var module1 = require('module1')
console.log(module1.foo())
console.log(module1.baz)

You can also override module.exports entirely to simply provide a single object upon require:

//glorp.js
module.exports = function () {
  this.foo = function () { return 'bar' }
  this.baz = 5
  return this // need to return `this` object here
}

Now you've got a nice prototype:

var g1 = new require('glorp')()
console.log(g1.foo())
console.log(g1.baz)

There are myriad other ways to play with module.exports and require. Just remember, require('foo') always returns the same instance even if you call it multiple times.

Note

For the following to work,

var g1 = new require('glorp')()
console.log(g1.foo())
console.log(g1.baz) 

this has to be returned in the function that is assigned to module.exports. Otherwise, you'll get a TypeError:

console.log(g1.foo())
          ^
TypeError: Cannot read property 'foo' of undefined
Tamzin Blake
  • 2,594
  • 20
  • 36
15

You can find the best answer in node.js source code. If someone is requiring your js module, your script turns into a function by node as follows (see src/node.js).

// require function does this..
(function (exports, require, module, __filename, __dirname) {
    ... your javascript contents...
});

Node will wrap your script. Then above script will be executed as follows:

//module.js
var args = [self.exports, require, self, filename, dirname];
return compiledWrapper.apply(self.exports, args);

So in your script,

exports is just module.exports.

In your script, you can add something to this exports object (functions..). require function will return this object. This is node.js's module system (commonJS specification).

But be careful not to modify module.exports. Otherwise your current exports will be meaningless.

jeremyko
  • 408
  • 5
  • 8
1

module is an object that represents what that particular source file would like to publicly expose. Instead of having something akin to header files in the c/c++ world, you describe what the module exports by defining this object. the node runtime then uses this object to determine what about your module is 'public.'

its a similar concept to exporting functions from a dll in the compiled world. you have to define explicitly what functions can be accessed by the outside world. this helps with encapsulation and lets your organize your libraries in a clean way.

Josh
  • 12,602
  • 2
  • 41
  • 47
0

Module's code is wrapped in module.exports (The module, maybe composed by other module). There are many ways to build a module, but this is one very common (and my personal favorite).

// Dependencies
// const module = require('module');

// Module object
var foo = {}

// Internal property
foo._a = 'a';

// "Public" property
foo.b = 'b';

// Method
foo.fu = function() { return 'fu' };

// Export
module.exports = foo;