Asynchronous Module Definition (AMD)

Three Problems

2012 Calendar

Stop Polluting the Global Namespace

Al Gore

Reduce, Reuse

Recycle

More of this

Microjs Screenshot

Clean Up the (Browser) Environment

Script Tags

Tools

Scopes

    
    var name = "Stewart";
    
    var vampire = function () {
        var name = "Pattinson";
        console.log("Robert " + name);
    };
    
    var wolf = function () {
        var name = "Lautner";
        console.log("Taylor " + name);
    };
    
    var human = function () {
        console.log("Kristen " + name);
    };

IIFE

Immediately Invoked Function Expression

(function () {
    var wavelength = 132, color = "#00f";
    ...


})();
    

IIFE

Immediately Invoked Function Expression

(function () {
    var wavelength = 132, color = "#00f";
    ...
    
    window.spaceLaserinator = { ... };
})();
    

"Namespaces"

CLTJS = window.CLTJS || {};    
    
(function () {
    var wavelength = 132, color = "#00f";
    ...

    CLTJS.spaceLaserinator = ... ;
})();

spaceLaserinator.js

(function () {
    
    var laser = CLTJS.laser;
    var inator = CTLJS.inator;
    
    ...
    inator.attach('<button>');
    laser.pointAt(window);
    CLTJS.spaceLaserinator = inator.with(laser);
})();

spaceLaserinator.js

(function (laser, inator) {
    
    ...
    inator.attach('<button>');
    laser.pointAt(window);
    CLTJS.spaceLaserinator = inator.with(laser);

})(CLTJS.laser, CLTJS.inator);
        
        
    

spaceLaserinator.js

(function (laser, inator) {
    
    ...
    inator.attach('<button>');
    laser.pointAt(window);
    CLTJS.spaceLaserinator = inator.with(laser);
        
})(CLTJS.frickinLaserBeam, CLTJS.inator);
        
        
    

spaceLaserinator.js

(function (laser, inator) {
    
    ...
    inator.attach('<button>');
    laser.pointAt(window);
    CLTJS.spaceLaserinator = inator.with(laser);
        
})(CLTJS.frickinLaserBeam, jQuery);
        
        
    

spaceLaserinator.js

(function (laser, inator) {

    /* 
      In reality,
      it takes 
      a minimum of
      62 lines of code
      to make a 
      half-decent
      space laserinator. 
    */
    
})(jQuery, CLTJS.frickinLaserBeam);
        
        
    

spaceLaserinator.js

define( [CLTJS.frickinLaserBeam, jQuery], 
    function (laser, inator) {
        ...
        CLTJS.spaceLaserInator = ...;
    }
);

var define = function(dependencies, callback) {
     callback.apply(dependencies);
};    

spaceLaserinator.js, AMD-style

define('spaceLaserInator', ['frickinLaserBeam', 'inator'], function (laser, inator) {
        ...
        return inator.with(laser);
    }
);

Pick-A-Colorinator

define('pickColor', ['constants', 'hsvToRgb'], function (constants, hsvToRgb) {
        
        return function (n) {
            var hue = n * constants.phi % 1;
            return hsvToRgb(hue, 0.5, 0.95);
        };
        
    }
);
define('constants', [], function () {

    return {
        phi: (1 + Math.sqrt(5)) / 2,
        e: 2.71828183,
        pi: 3.14159265
    };

})
    
define('hsvToRgb', [], function () {

    /* (c) 2008 Michael Jackson */
    return function (h, s, v) {
    
        var r, g, b;
        var i = Math.floor(h * 6);
        var f = h * 6 - i;
        var p = v * (1 - s);
        var q = v * (1 - f * s);
        var t = v * (1 - (1 - f) * s);

        switch(i % 6){
            case 0: r = v, g = t, b = p; break;
            case 1: r = q, g = v, b = p; break;
            case 2: r = p, g = v, b = t; break;
            case 3: r = p, g = q, b = v; break;
            case 4: r = t, g = p, b = v; break;
            case 5: r = v, g = p, b = q; break;
        }

        return [r * 255, g * 255, b * 255];
    }

});    
    

Optional Arguments are Optional

define('myModule', ['dependencyA', 'dependencyB'], function (a, b) {
    /* do stuff */
    return theModule;
});
    

Name is Optional

define(['dependencyA', 'dependencyB'], function (a, b) {
    /* do stuff */
    return theModule;
});
    

Dependencies Are Optional

define([], function () {
    /* do stuff */
    return theModule;
});
    

Dependencies Are Optional

define(function () {
    /* do stuff */
    return theModule;
});
    

Return Is Optional

define(function () {
    /* do stuff */
    
});
    

Shortcut for Modules that are Objects

define({
    splines: [12, 45, 19],
    reticulate: function () { ... }
});

Signature

define(name?, dependencies?, definitionFunction)

Example: compoundInterest.js

define(function () {

    /**
     * Basic compound interest
     * @author Miller Medeiros
     * @version 0.1.0 (2011/12/30)
     */
    function compoundInterest(presentValue, interestRate, nPeriods) {
        return presentValue * Math.pow(1 + interestRate, nPeriods);
    }

    return compoundInterest;

});

Example: randInt.js

define(['../number/MIN_INT', '../number/MAX_INT', '../number/toInt', './rand'], function(MIN_INT, MAX_INT, toInt, rand){

    /**
     * Gets random integer inside range or snap to min/max values.
     * @version 0.5.0 (2011/11/17)
     * @author Miller Medeiros / Fabio Caccamo
     */
    function randInt(min, max){
        min = min == null? MIN_INT : toInt(min);
        max = max == null? MAX_INT : toInt(max);
        // can't be max + 0.5 otherwise it will round up if `rand`
        // returns `max` causing it to overflow range.
        // -0.5 and + 0.49 are required to avoid bias caused by rounding
        return Math.round( rand(min - 0.5, max + 0.499999999999) );
    }

    return randInt;
});

Example: MAX_INT.js

/**
 * @constant Maximum 32-bit signed integer value. (2^31 - 1)
 * @version 0.1.0 (2011/10/21)
 * @author Miller Medeiros
 */
define(2147483647);

Loading with RequireJS

    require('./my-app/main-module');
    require({ 
        urlArgs: "bust=" +  (new Date()).getTime(), 
        baseUrl: '/path/to/my/app',
        ...
    },
    'main-module');
    <script 
        type="text/javascript" 
        src="scripts/require.js"
        data-main="main-module-name"
    ></script>
    <script type="text/javascript">
        require = {
            urlArgs: "bust=" +  (new Date()).getTime(), 
            baseUrl: '/path/to/my/app',
            ...
        }
    </script>

    <script 
        type="text/javascript" 
        src="scripts/require.js"
        data-main="main-module-name"
    ></script>

Concatenated builds with r.js

$ npm install require.js
$ node /path/to/r.js /path/to/main.js    
$ node /path/to/r.js -o build.js    

Almond

$ node r.js -o baseUrl=. name=path/to/almond.js include=main out=main-built.js wrap=true    
function () {
    
    // Almond
    var define = function (...) { ... };
    
    define('main', ['dep1', 'dep2'], function(dep1, dep2) { ... };
    define('dep1', function() { ... };
    define('dep2', ['dep2a'], function(dep2a) { ... };
    define('dep2a', function() { ... };
    
}(); // Look ma, no globals! 

Plugins!

define(['lib/mustache', 'text!path/to/template.html', 'json!some/data.json'], 
    function (mustache, view, data) {
        console.log(mustache.render(data, view)); 
    }
);
    
define(['order!love', 'order!marriage', 'order!baby/carriage'], 
    function (okcupid, bridesmaids, maclaren) {
        ...
    }
);
    

A plugin is just a module

define(['path/to/a/plugin!path/to/a/module', 'domReady!'], 
    function (module) {
        ...
    }
);

Node

Who's Using AMD?

.Next

Me

AMD

/

#