Node.JS Module Patterns

Using Simple Examples

Darren DeRidder / @73rhodes

Modules for n00bs

  • Node.JS - a Common.JS Module Implementation
  • Your code uses require to include modules.
  • Modules use exports to make things available.

Common.JS

An ecosystem for JavaScript outside the browser

  • Modules
  • Promises
  • Binary
  • Filesystem
  • Console
  • System
  • Testing
Kevin Dangoor, What Server Side JavaScript Needs
"What I’m describing here is not a technical problem. It’s a matter of people getting together and making a decision to step forward and start building up something bigger and cooler together."

Common.JS Implementations

  • MongoDB
  • CouchDB
  • SproutCore
  • Node.JS

The Simplest Module


 
    // hello.js
    console.log('Hello World');
 
                    

 
    // app.js
    require('./hello.js');
 
                    
implied facepalm...

Pattern 1: Define a Global


 
    // foo.js
    foo = function () {
      console.log('foo!');
    }
 
                    

 
    // app.js
    require('./foo.js');
    foo();
 
                    

don't pollute the global space

Pattern 2: Export an Anonymous Function


 
    // bar.js
    module.exports = function () {
      console.log('bar!');
    }
 
                    

 
    // app.js
    var bar = require('./bar.js');
    bar();
 
                    

Pattern 3: Export a Named Function


 
    // fiz.js
    exports.fiz = function () {
      console.log('fiz!');
    }
 
                    

 
    // app.js
    var fiz = require('./fiz.js').fiz;
    fiz();
 
                    

Pattern 4: Export an Anonymous Object


 
    // buz.js
    var Buz = function () {};

    Buz.prototype.log = function () {
      console.log('buz!');
    };

    module.exports = new Buz();
 
                    

 
    // app.js
    var buz = require('./buz.js');
    buz.log();
 
                    

Pattern 5: Export a Named Object


 
    // baz.js
    var Baz = function () {};

    Baz.prototype.log = function () {
      console.log('baz!');
    };

    exports.Baz = new Baz();
 
                    

 
    // app.js
    var baz = require('./baz.js').Baz;
    baz.log();
 
                    

Pattern 6: Export an Anonymous Prototype


 
    // doo.js
    var Doo = function () {};

    Doo.prototype.log = function () {
        console.log('doo!');
    }

    module.exports = Doo;
 
                

 
    // app.js
    var Doo = require('./doo.js');
    var doo = new Doo();
    doo.log();
 
                

Pattern 7: Export a Named Prototype


 
    // qux.js
    var Qux = function () {};

    Qux.prototype.log = function () {
      console.log('baz!');
    };

    exports.Qux = Qux;
 
                    

 
    // app.js
    var Qux = require('./qux.js').Qux;
    var qux = new Qux();
    qux.log();
 
                    

Pros and Cons

Named exports - one module, many exported things

Anonymous exports - simpler client interface

module.exports
VS
exports
exports VS. module.exports
  • exports is an alias to module.exports.
  • node automatically creates it as a convenient shortcut.
  • For assigning named properties, use either one.
  • 
     
    > module.exports.fiz = "fiz";
    > exports.buz = "buz";
    > module.exports === exports;
    true
                          

Warning

  • Assigning anything to exports directly (instead of exports.something) will overwrite the exports alias.
  • 
     
    > module.exports.qux = "qux";
    > exports
    { qux: "qux" }
    > exports === module.exports
    true
    > exports = "wobble wibble wubble!";
    > exports === module.exports
    false
    > exports
    "wobble wibble wubble!"
    > module.exports
    { qux: "qux" }
    // module.exports is canonical
     
                          

Thanks!

http://darrenderidder.github.io/talks/ModulePatterns