I was wondering what the difference between these snippets is.
var $ = require(\'jquery\');
var _ = require(\'underscore\');
var BackBone = require(\'backbon
The former snippet adheres to the CommonJS spec, which outlines how modules are to be exported/transported to be used in other modules.
So, you could write code which could look like this
src/ExpressModule.js
var express = require('express');
// do initialization
exports.express = express;
And then you can use it like this
src/UserExpressModule.js
var express = require('./ExpressModule');
// do something else
CommonJS spec was built primarily for server side environments, and by extension, is used in Node.js
On the other hand of the spectrum is AMD, most notably implemented by RequireJS. AMD was built for browser environments, or client-side code, and here you can use and define modules like the latter snippet in your code
A sample use could be like this
src/main.js
requirejs.config({
baseUrl: '../vendor'
path: '../src'
});
require(['jquery', 'underscore', 'backbone'], function($, _, Backbone) {
// do some client side computation here
});
You can then include this main.js
file in your index.html like so
<script data-main="src/main.js" src="vendor/require.js"></script>
Essentially, CommonJS and AMD are at their core specifications for modularizing Javascript, but are aimed at different execution environments.
Consider the first snippet, which is in the CommonJS style:
var $ = require('jquery');
var _ = require('underscore');
var BackBone = require('backbone');
These calls are synchronous calls: when require
returns, it returns the module you requested. CommonJS require
calls are synchronous. There is a proposal for supporting asynchronous forms of require
but as far as I can tell it has not progressed beyond the proposal level. Node.js used to have require.async
which has been removed. There's a package that implements it though. Using this package looks at lot like using AMD style modules.
Now, consider the second snippet, which is in the AMD style:
require(['jquery','underscore','backbone'],function ($, _, BackBone){
//code goes here
})
Since RequireJS implements the AMD type of module system, the above code works with RequireJS. This require
call is --- as suggested by the name Asynchronous Module Definition (AMD) --- asynchronous. You can't rely on the return value of require
to get a module value. You have to use a callback instead. The define
call works in a similar way but defines a module in addition to requiring modules.
Now, if you use RequireJS, it provides facilities that allow to use either style when you define modules so that you can define a module like this:
define(['jquery','underscore','backbone'],function ($, _, BackBone){
//code goes here
});
Or use something that looks more like the CommonJS idiom like this:
define(function (require) {
var $ = require('jquery');
var _ = require('underscore');
var BackBone = require('backbone');
//code goes here
});
It makes it really easy to convert a CommonJS style module to use with RequireJS: just wrap it with a define
call as above. There's a tool to help the conversion.
Behind the scenes, RequireJS reads the code of the callback in the 2nd form and creates a list of dependencies so that in the end it is interpreted like:
define(['require', 'jquery','underscore','backbone'], function (require) {
var $ = require('jquery');
var _ = require('underscore');
var BackBone = require('backbone');
//code goes here
})
It may be surprising (given that AMD is asynchronous) that the require
calls in the callback are synchronous. This is part of RequireJS's support for the CommonJS style. RequireJS supports a kind of synchronous require
call but with the following caveat: if the module is already defined before the call to the synchronous require
, then the synchronous require
returns the module's value, but otherwise it fails immediately. That is, it does not try to load a module. Because RequireJS interprets a module definition that uses the CommonJS style as I've shown above --- as if the dependencies were actually listed in the define
arguments --- then these modules are guaranteed to be loaded by the time the synchronous calls to require
are made.
Besides being able to use CommonJS modules in RequireJS (provided a wrapper is added), it is also possible to use modules designed for RequireJS in a CommonJS environment like Node.js. For instance, I've used node-amd-loader to load modules I've designed as AMD modules in Node.js.