Why should we add “shim” for AngularJS when using Require.js?

In computer programming, a shim is a small library that transparently intercepts API calls and changes the arguments passed, handles the operation itself, or redirects the operation elsewhere.Shims typically come about when the behavior of an API changes, thereby causing compatibility issues for older applications that still rely on the older functionality. In these cases, the older API can still be supported by a thin compatibility layer on top of the newer code. Shims can also be used to run programs on different software platforms than they were developed for.

-Wikipedia

When using require.js, we usually write as follows.

require.config({
    paths: {
        angular: './angular',
        app: './Content/app',
        ngAnimate: './Scripts/angular-animate',
        uiRouter: './Scripts/angular-ui-router'
    },
    shim: {
        angular: {
            exports: 'angular'
        }
    }
});

Let us dive little deeper and see why and when we need to use shim and what are the advantages of using it.

The rule is pretty simple: if a library/script/package/plugin is AMD-aware, then you don’t need a shim. (Actually, you must not use a shim for it.) If it is not AMD-aware, then you need a shim.

A library/etc is AMD-aware if it detects that an AMD loader is present and calls define to make itself known to the loader.

jQuery from about 1.8 onwards has not needed a shim because it calls define. Angular, on the other hand, does not call define.

To know whether a specific piece of code needs a shim, you can read its documentation or if the documentation is not clear on this, then you can check the source code for a call to define. For instance jQuery 1.11.0 has this code:

// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
if ( typeof define === "function" && define.amd ) {
    define( "jquery", [], function() {
        return jQuery;
    });
}

How it looks like will vary from one case to the other but the basic think you want to look for is the check that define exists, is a function, has the amd property set and the call to define.

(Note that jQuery is a special case where they decided to hard code the name of the module in the define call (first parameter: jquery). Generally the name of the module won’t be present in the define call but will be left for RequireJS to infer on the basis of the file name.).

Related Links:

Credits: StackOverflow Discussion

Leave a Reply

Your email address will not be published. Required fields are marked *