Javascript - AMD

javascript

https://github.com/umdjs/umd
https://github.com/systemjs/systemjs

https://www.linkedin.com/pulse/amd-vs-common-js-umd-damodaran-sathyakumar - done reading
https://auth0.com/blog/javascript-module-systems-showdown/ - done reading (03/15/2016)
https://addyosmani.com/writing-modular-js/
http://stackoverflow.com/questions/16521471/relation-between-commonjs-amd-and-requirejs
https://medium.com/@brianleroux/es6-modules-amd-and-commonjs-c1acefbe6fc0#.h8g11cs7l
https://dzone.com/articles/javascript-module-systems-showdown-commonjs-vs-amd
http://blog.millermedeiros.com/amd-is-better-for-the-web-than-commonjs-modules/
https://www.leanpanda.com/blog/2015/06/28/amd-requirejs-commonjs-browserify/
http://davidbcalhoun.com/2014/what-is-amd-commonjs-and-umd/
https://www.reddit.com/r/javascript/comments/3vqgai/eli5_commonjs_vs_amd_vs_es6/
http://tagneto.blogspot.com/2012/01/reply-to-tom-on-amd.html
http://unscriptable.com/2011/09/30/amd-versus-cjs-whats-the-best-format/

// JavaScript - AMD versus CommonJS:

AMD, Common JS are nothing but two styles of authoring Javascript code that help 
in making the code modular.  By saying modular, we mean to author code, such 
that it:

1. is a well encapsulated unit that performs a certain functionality,
2. has well defined single responsibility, 
3. has all its dependencies sorted out,
4. can be plugged into other modules
5. can be dynamically loaded / lazy loaded

AMD - (Asynchronous Module Definitions) made popular by Require JS, Curl JS is 
very much suited to the browser.  Common JS style, is something that is used in 
the Node world. 

That being said, it is possible to still author Common JS style modules for the 
browser & use it via Browserify and also use a simplified Common JS wrapper over 
the Require JS modules, to convert them into Common JS. 

define('mathOps', ['jquery','underscore'], function ($, _) {
  // methods
  function sum(a,b) {
    return a + b;
  };
  function multiply(a,b) {
    return a * b;
  }
  function divide(a,b) {
    return a / b;
  }
  function subtract(a,b) {
    return a - b;
  }
  function updateResult() {
    // use $ and _ to update something
  }

  // expose public methods
  return {
    sum: sum,
    multiply: multiply,
    division: division,
    updateResult: updateResult
  }
});

The above code is in AMD style.  It encapsulates the functionality within a 
define statement. It is a single responsibility module - performing math 
operations. Its dependencies are listed upfront - jQuery & Underscore JS. 

The callback within define doesn't execute until the dependencies are loaded / 
resolved. This module is pluggable and can be plugged as a dependency inside 
another module and re-used. The dependencies that are listed upfront - jQuery & 
underscore are aliased in the callback functions as - $ and _, for use within 
the module. 

In the ideal case, dependencies are loaded asynchronously (via injected scripts 
inside the <head> tag, so that they don' block the browser. Once the dependencies 
are loaded, the callback fires and returns the object with its functions inside 
the return statement.

But, in production apps, this doesn't work well and which is why require AMD 
modules need to be built into one single file and rendered - via the Require.js 
optimizer. 

var $ = require('jquery');
var _ = require('underscore');

// methods
function sum(a,b) {
  return a + b;
}
function multiply(a,b) {
  return a * b;
}
function divide(a,b) {
  return a / b;
}
function subtract(a,b) {
  return a - b;
}
function updateResult() {
  // use $ and _ to update something
}

// exposed public methods
module.exports = {
  sum: sum,
  multiply: multiply,
  divide: divide,
  subtract: subtract,
  updateResult: updateResult
};

The above code is in the Common JS style.  CommonJS is a style you will be 
familiar with if worked in Node. It’s also been gaining popularity on the client 
side with Browserify. Browserify is used to convert the common JS modules into a 
browser consumable format since the module.exports cannot be resolved on the 
client side unless a container object is created - what require JS does while it 
wraps the AMD modules in the simplify common JS format.

There are libraries used on the server side and client side. If you don't make 
your code compatible to both cases, then you'll find developers having trouble 
of using it and resorting to shims to get your library working. Classic example 
being - underscore.js in AMD. Underscore.js is not an AMD module and will have 
to be shimmed to be used.

There are engineers that feel CommonJS is better suited to server-side 
development which is one reason there's currently a level of disagreement over 
which format should be used as the de-facto standard.

So, until then, while authoring libraries, its important that you satisfy 
consumers of both these styles - at least till the near future where they decide 
which is the spec. This gives rise to UMD (Universal Module Definition).

(function (window,factory) {
  if (typeof define == 'function' && define.amd) {
    // AMD
    define(['jquery', 'underscore'], factory);
  } else if (typeof exports === 'object') {
    // Node, CommonJS
    module.exports = factory(require('jquery'), require('underscore'));
  } else {
    // Browser globals on window
    window.returnExports = factory(window.jQuery, window._);
  }
}(this, function ($, _) {
  // methods
  function sum(a,b) {
    return a + b;
  };
  function multiply(a,b) {
    return a * b;
  };
  function division(a,b) {
    return a / b;
  };
  function subtract(a,b) {
    return a - b;
  };
  function updateResult() {
    // use $ and _ to update something
  };

  // exposed public methods
  return {
    sum: sum,
    multiply: multiply,
    divide: divide,
    subtract: subtract,
    updateResult: updateResult
  }
}));

This is a universal pattern that supports both the styles mentioned above. The 
same module is now re-written below in the UMD format.

It is a bit of a clutter, but, your library supports both the worlds and all are 
happy now!

AMD takes a browser-first approach, using asynchronous behavior and backwards 
compatibility but doesn't have a File I/O concept. It supports objects, 
functions, constructors, strings, JSON and many other types of modules, 
running natively in the browser. It can be used to lazy load / defer the 
loading of dependencies. 

CommonJS on the other hand takes a server-first approach, assuming synchronous 
behavior, no globals and it attempts to cater for the future - server side. So, 
Common JS supports unwrapped modules, freeing you of the define() wrapper that 
AMD enforces.

CommonJS modules were designed with server development in mind. Naturally, the 
API is synchronous. In other words, modules are loaded at the moment and in the 
order they are required inside a source file.

CommonJS Pros:

1. Simple: a developer can grasp the concept without looking at the docs.
2. Dependency management is integrated: modules require other modules and get 
   loaded in the needed order.
3. The require statement can be called anywhere and modules can be loaded 
   programmatically.
4. Circular dependencies are supported.

CommonJS Cons:

1. Synchronous API makes it not suitable for certain uses (client-side).
2. One file per module.
3. Browsers require a loader library or transpiling.
4. No constructor function for modules (Node supports this though).
5. Hard to analyze for static code analyzers.

For the client there are currently two popular options: webpack and browserify. 
Browserify was explicitly developed to parse Node-like module definitions (many 
Node packages work out-of-the-box with it!) and bundle your code plus the code 
from those modules in a single file that carries all dependencies. Webpack on 
the other hand was developed to handle creating complex pipelines of source 
transformations before publishing. This includes bundling together CommonJS 
modules.

AMD was born out of a group of developers that were displeased with the 
direction adopted by CommonJS. In fact, AMD was split from CommonJS early in its 
development. The main difference between AMD and CommonJS lies in its support 
for asynchronous module loading.

AMD Pros:

1. Asynchronous loading (better startup times).
2. Circular dependencies are supported.
3. Compatibility for require and exports.
4. Dependency management fully integrated.
5. Modules can be split in multiple files if necessary.
6. Constructor functions are supported.
7. Plugin support (custom loading steps).

AMD Cons:

1. Slightly more complex syntactically.
2. Loader libraries are required unless transpiled.
3. Hard to analyze for static code analyzers.

Using require.js is pretty straightforward: include the library in your HTML 
file and use the data-main attribute to tell require.js which module should be 
loaded first.

Fortunately, the ECMA team behind the standardization of JavaScript decided to 
tackle the issue of modules. The result can be seen in the latest release of the 
JavaScript standard: ECMAScript 2015 (previously known as ECMAScript 6). 
The result is syntactically pleasing and compatible with both synchronous and 
asynchronous modes of operation.

//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}
//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

The above code show a lib.js file.  The name of the file probably does not 
matter.  Inside this file, we export two functions (square, and diag).  Inside
the main.js file, we import these two functions and use them.

The import directive can be used to bring modules into the namespace. This 
directive, in contrast with require and define is not dynamic (i.e. it cannot 
be called at any place). The export directive, on the other hand, can be used to 
explicitly make elements public.

The static nature of the import and export directive allows static analyzers to 
build a full tree of dependencies without running code. ES2015 does support 
dynamic loading of modules:

System.import('some_module')
      .then(some_module => {
          // Use some_module
      })
      .catch(error => {
          // ...
      });

In truth, ES2015 only specifies the syntax for the dynamic and static module 
loaders. In practice, ES2015 implementations are not required to do anything 
after parsing these directives. Module loaders such as System.js are still 
required until the next ECMAScript spec is released.

This solution, by virtue of being integrated in the language, lets runtimes 
pick the best loading strategy for modules. In other words, when asynchronous 
loading gives benefits, it can be used by the runtime.

ES2015 Pros:

1. Synchronous and asynchronous loading supported.
2. Syntactically simple.
3. Support for static analysis tools.
4. Integrated in the language (eventually supported everywhere, no need for libraries).
5. Circular dependencies supported.

ES2015 Cons:

1. Still not supported everywhere.  Fortunately many transpilers do support 
   modules and a polyfill is also available. Currently, the ES2015 preset for 
   Babel can handle modules with no trouble.

System.js: a universal module loader that supports CommonJS, AMD and ES2015 
modules. It can work in tandem with transpilers such as Babel or Traceur and 
can support Node and IE8+ environments. Using it is a matter of loading System.js 
in your code and then pointing it to your base URL:

<script src="system.js"></script>
<script>
  // set our baseURL reference path
  System.config({
    baseURL: '/app',
    // or 'traceur' or 'typescript'
    transpiler: 'babel',
    // or traceurOptions or typescriptOptions
    babelOptions: {

    }
  });

  // loads /app/main.js
  System.import('main.js');
</script>

As System.js does all the job on-the-fly, using ES2015 modules should generally 
be left to a transpiler during the build step in production mode. When not in 
production mode, System.js can call the transpiler for you, providing seamless 
transition between production and debugging environments.

What are the available AMD libraries?

  1. curl.js: http://davidwalsh.name/curljs
  2. Jam: http://net.tutsplus.com/tutorials/javascript-ajax/frictionless-amd-with-jam/
  3. RequireJS
  4. Script.js: http://dustindiaz.com/scriptjs
  5. StackJS: http://www.position-absolute.com/articles/stackjs-a-javascript-module-loader-and-dependencies-handler/
  6. StackJS: http://blogs.sitepoint.com/2010/10/27/throwing-better-errors-using-stack
  7. YepNope: http://blogs.sitepoint.com/2011/03/08/regressive-enhancement-with-modernizr-and-yepnope/
  8. YepNope: http://net.tutsplus.com/tutorials/javascript-ajax/easy-script-loading-with-yepnope-js/
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License