Requirejs why and when to use shim config
A primary use of shim is with libraries that don't support AMD, but you need to manage their dependencies. For example, in the Backbone and Underscore example above: you know that Backbone requires Underscore, so suppose you wrote your code like this:
require(['underscore', 'backbone']
, function( Underscore, Backbone ) {
// do something with Backbone
}
RequireJS will kick off asynchronous requests for both Underscore and Backbone, but you don't know which one will come back first so it's possible that Backbone would try to do something with Underscore before it's loaded.
NOTE: this underscore/backbone example was written before both those libraries supported AMD. But the principle holds true for any libraries today that don't support AMD.
The "init" hook lets you do other advanced things, e.g. if a library would normally export two different things into the global namespace but you want to redefine them under a single namespace. Or, maybe you want to do some monkey patching on a methods in the library that you're loading.
More background:
- Upgrading to RequireJS 2.0 gives some history on how the order plugin tried to solve this in the past.
- See the "Loading Non-Modules" section of This article by Aaron Hardy for another good description.
As per RequireJS API documentation, shim lets you
Configure the dependencies, exports, and custom initialization for older, traditional "browser globals" scripts that do not use define() to declare the dependencies and set a module value.
- Configuring dependencies
Lets say you have 2 javascript modules(moduleA and moduleB) and one of them(moduleA) depends on the other(moduleB). Both of these are necessary for your own module so you specify the dependencies in require() or define()
require(['moduleA','moduleB'],function(A,B ) {
...
}
But since require itself follow AMD, you have no idea which one would be fetched early. This is where shim comes to rescue.
require.config({
shim:{
moduleA:{
deps:['moduleB']
}
}
})
This would make sure moduleB is always fetched before moduleA is loaded.
- Configuring exports
Shim export tells RequireJS what member on the global object (the window, assuming you're in a browser, of course) is the actual module value. Lets say moduleA adds itself to the window
as 'modA'(just like jQuery and underscore does as $ and _ respectively), then we make our exports value 'modA'.
require.config({
shim:{
moduleA:{
exports:'modA'
}
}
It will give RequireJS a local reference to this module. The global modA will still exist on the page too.
-Custom initialization for older "browser global" scripts
This is probably the most important feature of shim config which allow us to add 'browser global', 'non-AMD' scripts(that do not follow modular pattern either) as dependencies in our own module.
Lets say moduleB is plain old javascript with just two functions funcA() and funcB().
function funcA(){
console.log("this is function A")
}
function funcB(){
console.log("this is function B")
}
Though both of these functions are available in window scope, RequireJS recommends us to use them through their global identifier/handle to avoid confusions. So configuring the shim as
shim: {
moduleB: {
deps: ["jquery"],
exports: "funcB",
init: function () {
return {
funcA: funcA,
funcB: funcB
};
}
}
}
The return value from init function is used as the module export value instead of the object found via the 'exports' string. This will allow us to use funcB in our own module as
require(["moduleA","moduleB"], function(A, B){
B.funcB()
})
Hope this helped.