CommonJS is a group with a goal of building up the JavaScript ecosystem. It has a mailing list of developers, just like you, who are dedicated to promoting portability and interoperability of JavaScript programs across JavaScript environments, from the server to the browser.
JavaScript doesn't have a built-in module system (not yet anyway), so the developers on the mailing list created their own. Traditional CommonJS modules might look like this:
math.js:
exports.add = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) { sum += args[i++]; } return sum; };
increment.js:
var add = require('math').add; exports.increment = function(val) { return add(val, 1); };
program.js:
var inc = require('increment').increment; var a = 1; inc(a); // 2
If you look closely at the example above, you might notice that
require
is synchronous. That is, we're assuming that
the module system will able to determine whether a given module is
available (and initialize it) before the require call returns.
As it turns out, this is highly problematic for the browser.
Hands down, the best way to load JavaScript into the browser is by inserting
<script>
tags into the document. But script tag insertion
is inherently asynchronous. As a result traditional CommonJS
modules aren't going to work in this kind of environment.
One option would be to have a server-side component perform static analysis on the module code and return the module along with a list of its dependencies to the browser. This works pretty well, but it necessitates the installation of an external component along with all of the infrastructure that it depends on.
Instead, we wrap the module definition in a small amount of boilerplate, like this:
define(function(require, exports, module) { // The module code goes here });
The boilerplate gives the module loader the opportunity to perform static analysis on the module code and dynamically generate a list of dependencies that must be resolved before the module code executes.
In order for static analysis to work, though, you'll need to follow a few simple rules.
If we wrap the traditional modules that we looked at previously, we get this:
math.js:
define(function(require, exports, module) { exports.add = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) { sum += args[i++]; } return sum; }; });
increment.js:
define(function(require, exports, module) { var add = require('math').add; exports.increment = function(val) { return add(val, 1); }; });
program.js:
define(function(require, exports, module) { var inc = require('increment').increment; var a = 1; inc(a); // 2 });
Some explanations are forked from FlyScript's Documentation. Thanks very much to Kevin H. Smith.