doc: improve module documentation
authorRyan Graham <r.m.graham@gmail.com>
Sat, 26 Oct 2013 05:03:02 +0000 (22:03 -0700)
committerBen Noordhuis <info@bnoordhuis.nl>
Sun, 27 Oct 2013 10:47:11 +0000 (11:47 +0100)
Expands on when to use module.exports vs. exports. This is a recurring
question on mailing list and continues to confuse new devs.

doc/api/globals.markdown
doc/api/modules.markdown

index cd6a33d3a8fd7e873bf5a34c6aecf33590f9186b..4fb8613382303da6ddf117d10d7fb836917bad55 100644 (file)
@@ -124,7 +124,9 @@ Example: running `node example.js` from `/Users/mjr`
 * {Object}
 
 A reference to the current module. In particular
-`module.exports` is the same as the `exports` object.
+`module.exports` is used for defining what a module exports and makes
+available through `require()`.
+
 `module` isn't actually a global but rather local to each module.
 
 See the [module system documentation][] for more information.
@@ -133,10 +135,10 @@ See the [module system documentation][] for more information.
 
 <!-- type=var -->
 
-A reference to the `module.exports` object which is shared between all
-instances of the current module and made accessible through `require()`.
+A reference to the `module.exports` that is shorter to type.
 See [module system documentation][] for details on when to use `exports` and
 when to use `module.exports`.
+
 `exports` isn't actually a global but rather local to each module.
 
 See the [module system documentation][] for more information.
index c551cb01083e0c702423485e91284cd516ae806d..a9c503448e807d9286a969aa693f9e8964bbf712 100644 (file)
@@ -27,26 +27,33 @@ The contents of `circle.js`:
     };
 
 The module `circle.js` has exported the functions `area()` and
-`circumference()`.  To export an object, add to the special `exports`
-object.
+`circumference()`.  To add functions and objects to the root of your module,
+you can add them to the special `exports` object.
 
-Note that `exports` is a reference to `module.exports` making it suitable
-for augmentation only. If you are exporting a single item such as a
-constructor you will want to use `module.exports` directly instead.
+Variables local to the module will be private, as though the module was wrapped
+in a function. In this example the variable `PI` is private to `circle.js`.
 
-    function MyConstructor (opts) {
-      //...
-    }
+If you want the root of your module's export to be a function (such as a
+constructor) or if you want to export a complete object in one assignment
+instead of building it one property at a time, assign it to `module.exports`
+instead of `exports`.
+
+Below, `bar.js` makes use of the `square` module, which exports a constructor:
 
-    // BROKEN: Does not modify exports
-    exports = MyConstructor;
+    var square = require('./square.js');
+    var mySquare = square(2);
+    console.log('The area of my square is ' + mySquare.area());
 
-    // exports the constructor properly
-    module.exports = MyConstructor;
+The `square` module is defined in `square.js`:
 
-Variables
-local to the module will be private. In this example the variable `PI` is
-private to `circle.js`.
+    // assigning to exports will not modify module, must use module.exports
+    module.exports = function(width) {
+      return {
+        area: function() {
+          return width * width;
+        }
+      };
+    }
 
 The module system is implemented in the `require("module")` module.
 
@@ -232,18 +239,21 @@ would resolve to different files.
 * {Object}
 
 In each module, the `module` free variable is a reference to the object
-representing the current module.  In particular
-`module.exports` is accessible via the `exports` module-global.
-`module` isn't actually a global but rather local to each module.
+representing the current module.  For convenience, `module.exports` is
+also accessible via the `exports` module-global. `module` isn't actually
+a global but rather local to each module.
 
 ### module.exports
 
 * {Object}
 
 The `module.exports` object is created by the Module system. Sometimes this is not
-acceptable, many want their module to be an instance of some class. To do this
-assign the desired export object to `module.exports`. For example suppose we
-were making a module called `a.js`
+acceptable; many want their module to be an instance of some class. To do this
+assign the desired export object to `module.exports`. Note that assigning the
+desired object to `exports` will simply rebind the local `exports` variable,
+which is probably not what you want to do.
+
+For example suppose we were making a module called `a.js`
 
     var EventEmitter = require('events').EventEmitter;
 
@@ -277,6 +287,28 @@ y.js:
     var x = require('./x');
     console.log(x.a);
 
+#### exports alias
+
+The `exports` variable that is available within a module starts as a reference
+to `module.exports`. As with any variable, if you assign a new value to it, it
+is no longer bound to the previous value.
+
+To illustrate the behaviour, imagine this hypothetical implementation of
+`require()`:
+
+    function require(...) {
+      // ...
+      function (module, exports) {
+        // Your module code here
+        exports = some_func;        // re-assigns exports, exports is no longer
+                                    // a shortcut, and nothing is exported.
+        module.exports = some_func; // makes your module export 0
+      } (module, module.exports);
+      return module;
+    }
+
+As a guideline, if the relationship between `exports` and `module.exports`
+seems like magic to you, ignore `exports` and only use `module.exports`.
 
 ### module.require(id)