Relation Between Commonjs, Amd and Requirejs

Relation between CommonJS, AMD and RequireJS?

RequireJS implements the AMD API (source).

CommonJS is a way of defining modules with the help of an exports object, that defines the module contents. Simply put, a CommonJS implementation might work like this:

// someModule.js
exports.doSomething = function() { return "foo"; };

//otherModule.js
var someModule = require('someModule'); // in the vein of node
exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };

Basically, CommonJS specifies that you need to have a require() function to fetch dependencies, an exports variable to export module contents and a module identifier (which describes the location of the module in question in relation to this module) that is used to require the dependencies (source). CommonJS has various implementations, including Node.js, which you mentioned.

CommonJS was not particularly designed with browsers in mind, so it doesn't fit in the browser environment very well (*I really have no source for this--it just says so everywhere, including the RequireJS site.*) Apparently, this has something to do with asynchronous loading, etc.

On the other hand, RequireJS implements AMD, which is designed to suit the browser environment (source). Apparently, AMD started as a spinoff of the CommonJS Transport format and evolved into its own module definition API. Hence the similarities between the two. The new feature in AMD is the define() function that allows the module to declare its dependencies before being loaded. For example, the definition could be:

define('module/id/string', ['module', 'dependency', 'array'], 
function(module, factory function) {
return ModuleContents;
});

So, CommonJS and AMD are JavaScript module definition APIs that have different implementations, but both come from the same origins.

  • AMD is more suited for the browser, because it supports asynchronous loading of module dependencies.
  • RequireJS is an implementation of AMD, while at the same time trying to keep the spirit of CommonJS (mainly in the module identifiers).

To confuse you even more, RequireJS, while being an AMD implementation, offers a CommonJS wrapper so CommonJS modules can almost directly be imported for use with RequireJS.

define(function(require, exports, module) {
var someModule = require('someModule'); // in the vein of node
exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };
});

Difference between RequireJS and CommonJS

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.

supporting both CommonJS and AMD

Here is a list of various cross-compatible module formats.

I suspect that the one you're looking for is what they're calling "commonjsStrict.js"

what are the advantages of using an AMD like requirejs or commonjs modules in javascript?

In my opinion, there are three rather important reasons:

You can create and re-use modules without polluting the global namespace. The more polluted your global namespace is, the bigger the chance of a function/variable collision. That means you define a function called "foo" and another developer defines the function "foo" = one of the functions gets overwritten.

You can structure your code into separate folders and files and requirejs will load them asynchronously when needed, so everything just works.

You can build for production. RequireJS comes with its own build tool called R.JS that will concat and uglify your javascript modules into a single (or multiple) packages. This will improve your page speed as the user will have to make less script calls and load less content (as your JS is uglified).

You can take a look at this simple demo project: https://c9.io/peeter-tomberg/requirejs (in cloud9ide).

To build your modules into a single app, all you have to do is have requirejs npm package installed and run the command: r.js -o build/build.properties.js

If there are any questions, ask away.

Edit:

In development, having all modules in separate files is just a good way to structure and manage your code. It also helps you in debugging (e.g. error on "Module.js line 17" instead of "scripts.js line 5373").

For production, you should use the build tool to concat and uglify the javascript into a single file. This will help the page load quicker as you are making less requests. Every request you make to load something slows down your page. The slower your page, the less points Google gives you. The slower the page, the more frustrated your users will be. The slower your page, the less sales you will get.

If you wish to read more about web page performance, look at http://developer.yahoo.com/performance/rules.html

How do you author a module that is compatible with CommonJS, AMD and Browser in ES6 with Babel?

So there is no real way to include ES6 modules in a universal module definition because ES6 modules are strictly one per file and all import and export statements must be at the top level.

When the loader spec is done there will likely be a way to add a module into the registry and that will be how you'd include ES6 modules in a UMD, until then, since no browsers actually support ES6 modules your only targets are AMD and CommonJS, but you should be using one of the many compilers or trsnspilers like browserify or Babel to do that for you.

Converting CommonJS to AMD

The Problem

shim cannot do as much as you want it to do. When RequireJS evaluates the symbol you give in exports, it evaluates it in the global space. So using exports works fine if you can access the variable you want to export from the global space. If library foo exports Foo into the global space, that works fine.

What you are trying to do is have a module that exports its API through module work with a shim. This cannot work because RequireJS cannot guess that the module being loaded requires that a global module object be already available to the module being loaded. In the simplest case, loading such module will result in a ReferenceError because module does not exist. There would be ways to fake the module.exports thing that would work in the most trivial cases but it would not work as a general solution.

A Solution

You can use r.js to convert files that are written in the CommonJS format to what RequireJS needs. It is documented here. The documentation gives the following synopsis:

node r.js -convert path/to/commonjs/modules/ path/to/output

You should also read this part of the README for some caveats.

Is it possible to mix AMD and CommonJS modules within same Typescript project

is there a way to mix AMD and CommonJS modules in the same Typescript project (preferably using NodejsTools)

Yes. Use grunt-ts. See https://github.com/basarat/demo-fullstack/tree/master/src specifically the gruntfile common files : https://github.com/basarat/demo-fullstack/blob/master/src/Gruntfile.js#L4-L6 commonjs : https://github.com/basarat/demo-fullstack/blob/master/src/Gruntfile.js#L26 amd : https://github.com/basarat/demo-fullstack/blob/master/src/Gruntfile.js#L37

Define module with dependencies for AMD (requirejs) and Common.js (Node.js) and global scope

Instead of exposing dependencies as globals, pass them as arguments to your factory.

For example:

(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([ 'module', 'moment' ], function (module, moment) {
module.exports = factory(moment);
});
} else if (typeof module === 'object') {
module.exports = factory(require('moment'));
} else {
root.formatDate = factory(root.moment);
}
}(this, function (moment) {

}));

Check out the Universal Module Definition (UMD) recipes at https://github.com/umdjs/umd



Related Topics



Leave a reply



Submit