Search code examples
javascriptnode.jscommonjs

What's the difference between these two module.exports?


So the first one being something like:

myFile.js

var name = "Peter";

module.exports.sayHello = function () {
  console.log('Hello ' + name);
}

And the second one

myFile.js

module.exports = function () {

  var name = 'Mary';

  function sayHello () {
    console.log('Hello ' + name);
  }

  return {
    sayHello : sayHello
  };

}();

Essentially it's the same thing right? If not, what's the difference and what's the pros and cons of each method?


Solution

  • Why do we need modules?

    When you have a code like this:

    // module 1
    var a = 1;
    var x = function (){
        return a;
    };
    
    // module 2
    var a = 2; // duplicated variable declaration
    var y = function (){
        return a;
    };
    
    // main
    console.log(x()); // BUG: this should read value from module 1 instead of module 2
    console.log(y());
    

    It will lead to error, since the a variable was already taken by the first module. You need to define modules somehow.

    Using a prefix

    By old-style procedural programming you would add a prefix to separate modules:

    // module 1
    var m1_a = 1;
    var m1_x = function (){
        return m1_a;
    };
    
    // module 2
    var m2_a = 2;
    var m2_y = function (){
        return m2_a;
    };
    
    // main
    console.log(m1_x());
    console.log(m2_y());
    

    But this makes the code less readable.

    Using closures

    By javascript you have closures, which make things a little bit easier:

    // module 1
    var x = (function (){
        var a = 1;
        var x = function (){
            return a;
        };
        return x;
    })();
    
    // module 2
    var y = (function (){
        var a = 2;
        var y = function (){
            return a;
        };
        return y;
    })();
    
    // main
    console.log(x());
    console.log(y());
    

    But still you have different modules in a single file, so that file will be really big and hard to maintain.

    Using the node.js module loader

    By node.js you can move the code of different modules to separate files, so it will be easy to maintain the code of different modules, since you will be able to find the relevant part of the code much faster:

    m1.js

    var a = 1;
    var x = function (){
        return a;
    };
    module.exports = x;
    

    m2.js

    var a = 2;
    var y = function (){
        return a;
    };
    module.exports = y;
    

    main.js

    var x = require("m1");
    var y = require("m2");
    
    console.log(x());
    console.log(y());
    

    You can do the same in the browser

    The simplest node.js style browser module loader I could come up with so far, is this:

    var cache = {};
    
    function require(name){
        if (name in cache)
            return cache[name];
        var uri = "./" + name + ".js";
        var xhr = new XMLHttpRequest();
        xhr.open("GET", uri, false);
        xhr.send(null);
        var moduleCode = xhr.responseText;
        var fn = new Function("module", moduleCode);
        var module = {};
        fn(module);
        cache[name] = module.exports;
        return cache[name];
    };
    

    Ofc. it is much safer to use browserify, webpack, require.js and other more sophisticated libs, I just wanted to show you, it is not that hard to write a loader.

    What did we learn from all of this?

    Both node.js modules and closures are for modularization. You should not mix them, since they solve the same problem, and mixing them will lead only to confusion!