AMD use with UWA

What is AMD?

AMD (Asynchronous Module Definition https://github.com/amdjs/amdjs-api/wiki/AMD) is a format for writing modular JavaScript in the browser. The AMD module format itself is a proposal for defining modules where both the module and its dependencies can be asynchronously loaded. It has a number of distinct advantages including being both asynchronous and highly flexible by nature which removes the tight coupling one might commonly find between code and module identity.

define and require

The two key concepts you need to be aware of are the idea of a define method for facilitating module definition and a require method for handling dependency loading.

define is used to define modules using the following signature:

define(
    module_id,
    [dependencies],
    factory /*function for instantiating the module or object*/
);

The dependencies argument represents an array of dependency names which are required by the module you are defining and the third argument ('factory') is a function that's executed to instantiate your module. A barebones module could be defined as follows:

define(
    'myProject/myPackage/myModule',
    [
        'UWA/Core',
        'UWA/Element'
    ],
    function ( Core, Element ) {

        // Module dependencies (UWA/Core and UWA/Element) are mapped to function arguments

        // return a value that defines the module export
        // (i.e the functionality we want to expose for consumption)

        // create your module here
        var myModule = {
            doStuff: function() {

               var myElement = new Element('div', {
                    class:'myClass'
               });

               Core.log('just created a new div');
            }
        }

        return myModule;
});

require on the other hand is typically used to load code in two cases:

  • Load module(s) in non-reusable code:
// Consider that 'UWA/Core' and 'UWA/Element' are two external modules.
// In this example, the 'exports' from the two modules loaded are passed as
// function arguments to the callback (Core and Element)
// so that they can similarly be accessed.

require(['UWA/Core', 'UWA/Element'], function ( Core, Element ) {
        // rest of your code here
        Core.log('inside the require function');
});
  • Load module (lets say A) inside another module (lets say B) but only in some cases of the B module's logic (not before B module's initialization):
define('myProject/myPackage/myModule', ['UWA/Core'], function (Core) {

    var myModule = {
            doStuff:function(){
                Core.log('here i can only use core');
            }
        };

    if(myModule.elementIsNeededToDoSomething){
        require(['UWA/Element'], function (Element) {

            myModule.myElement = new Element('div',{
                class:'myClass'
            });

            Core.log('here i could use Element thanks to the above require')
        });
    }

    return myModule;
});

AMD loaders

The define and require methods are implemented by the AMD loaders. AMD loaders are very lighweight JavaScript libraries and UWA currently embeds a version of curl.js, but a change would have no impact on module definitions code.

Conclusions

The above are very trivial examples of just how useful AMD modules can truly be, but they hopefully provide a foundation for understanding how they work.

To sum up, here are the main advantages of using the AMD format for your applications:

  • Provides a clear proposal for how to approach defining flexible modules that can hide logic from or expose logic to the other modules.
  • Significantly cleaner than the global namespace and <script> tag solutions. There's a clean way to declare stand-alone modules and dependencies they may have.
  • Module definitions are encapsulated, helping us avoid pollution of the global namespace (which enhances overall JavaScript performance).
  • Possibility to load scripts lazily/on-demand, diminishing application bootstrap time.
  • Provides further optimization possibilities (better minification, grouped modules loading by common usage...) handled at build time.

The whole UWA js runtime is, as are many enterprise-level applications and frameworks, entirely implemented using the AMD format.