-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Differences between the simplified CommonJS wrapper and standard AMD define
RequireJS has many ways of defining a module, this document will cover the 2 ways of defining a module which contain dependencies, the standard AMD define and the simplified CommonJS wrapper, both ways can be used on the same project and toggled at will, but it's important to understand how both patterns differs and the problems that may arise.
The basic definition of an AMD module is like this:
define(['foo', 'foo/bar'], function(foo, bar){
return {
doSomething : function(){
console.log(foo + bar);
}
};
});
This means that modules foo
and foo/bar
will be loaded (if not available
yet) before the definition function gets called and it will pass both modules as
arguments to the definition function. More about it on the RequireJS API
page
- RequireJS reads the dependency array.
- Then it checks if each module was already registered for the current context:
- If module was registered uses it;
- Otherwise:
- resolve the ID into a URI by checking the paths.config and current module path;
- loads script;
- If AMD module, repeat steps till all the dependencies are loaded.
- After all the dependencies are ready it calls the definition function passing the dependencies as arguments, it will then register the module as the value returned by the definition function.
If you prefer to author your modules as if it was a CommonJS module (specially if you have a very large dependency array) you can use the simplified CommonJS wrapper.
define(function(require, exports, module){
var foo = require('foo'),
bar = require('foo/bar');
exports.doSomething = function(){
console.log(foo + bar);
};
});
A module is only treated as a CJS module if it doesn't contain a dependency array and the definition function contain at least one parameter.
More info about the Simplified CJS Wrapper at RequireJS documentation.
- RequireJS checks if
define
was called without a dependency array. - Then it checks if the definition function contains any parameters by
reading
Function.prototype.length
.- If it contains, treats the module as CJS:
- Call
Function.prototype.toString()
and read all the synchronousrequire()
calls inside the definition function. - Load all dependencies like if it was on the dependency list of a standard AMD module (see step 2 of "standard AMD define").
- After dependencies are ready it calls the definition function passing
the special modules
require
,exports
andmodule
as arguments, then registers module as returned value or as value set asmodule.exports
or theexports
object itself.
- Call
- If not, execute definition function and register module as returned value. (standard AMD without any dependencies)
- If it contains, treats the module as CJS:
On a standard AMD module you can use a synchronous require()
as long as the
module was already registered for that context:
define(['require', 'lorem/ipsum'], function(require){
// since 'lorem/ipsum' is on the dependency list it will be registered
// before calling the definition function, so the synchronous require will
// also work
console.log( require('lorem/ipsum') );
});
But this would fail if the module dolor/amet
wasn't registered yet:
define(['require'], function(require){
console.log( require('dolor/amet') );
});
Since we are passing a dependency array as first argument of the define
call
it will treat the module as a standard AMD module, so it won't read the
definition function content to figure out the dependencies before calling it.
You would get the following error:
Uncaught Error: Module name 'dolor/amet' has not been loaded yet for context: _
But if you use the Simplified CommonJS Wrapper instead it would load the dependency before calling the definition function:
define(function(require){
// this will work since RequireJS will treat module as CJS
console.log( require('dolor/amet') );
});
The special modules require
, exports
and module
are also available for
standard AMD modules.
define(['exports'], function(exports){
//add properties to the exports object as if the module was a CJS module
exports.foo = 'bar';
exports.lorem = function(){
console.log('ipsum');
};
});
Properties added to the exports
object will be on the public interface of the
module, no need to return any value.
This module gives you information about the module ID and location of the current module:
define(['module'], function(module){
console.log(module.id);
console.log(module.uri);
});
The previous examples used the require
module to load other dependencies but
it also contains.
-
require.toUrl(moduleName)
: It will return a full path to the resource, obeying any RequireJS configuration.
If you have more questions check RequireJS mailing list and the #requirejs IRC channel on freenode.net.