Search code examples
javascriptbackbone.jsrequirejsamd

Are RequireJS "shim" needed for Backbone.js?


It seems that recent versions of Backbone.js and Underscore.js support AMD.

So am I correct in assuming that it is no longer needed to "shim" these libraries in the require.js configuration?


Solution

  • Yes, you are correct, no shim needed. And it's easy to test, here's the simplest setup:

    requirejs.config({
        /**
         * Paths to lib dependencies.
         *
         * Use non-minified files where possible as they will be minified (and
         * optimized via uglify) on release build (r.js)
         */
        paths: {
            "jquery": "libs/jquery/dist/jquery",
            "underscore": "libs/underscore/underscore",
            "backbone": "libs/backbone/backbone",
        },
    
        deps: ["app"] // starts the app
    });
    

    And to make sure it works and it's not the global Underscore that's used:

    // I'm using Underscore as to avoid conflicting with the global _
    // but you could use _ as the name for the local variable as well.
    define(['backbone', 'underscore'], function(Backbone, Underscore) {
        console.log("Backbone:", Backbone.VERSION)
        console.log("Local Underscore:", Underscore.VERSION);
        console.log("Global Underscore:", _.VERSION, _ === Underscore);
    });
    

    For Backbone, it's clear in the source that it supports AMD by default:

    // Set up Backbone appropriately for the environment. Start with AMD.
    if (typeof define === 'function' && define.amd) {
      define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
        // Export global even in AMD case in case this script is loaded with
        // others that may still expect a global Backbone.
        root.Backbone = factory(root, exports, _, $);
      });
    

    As for Underscore, it is registering itself at the end:

    // AMD registration happens at the end for compatibility with AMD loaders
    // that may not enforce next-turn semantics on modules. Even though general
    // practice for AMD registration is to be anonymous, underscore registers
    // as a named module because, like jQuery, it is a base library that is
    // popular enough to be bundled in a third party lib, but not be part of
    // an AMD load request. Those cases could generate an error when an
    // anonymous define() is called outside of a loader request.
    if (typeof define === 'function' && define.amd) {
      define('underscore', [], function() {
        return _;
      });
    }
    

    Same thing with jQuery:

    // 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.
    
    // Note that for maximum portability, libraries that are not jQuery should
    // declare themselves as anonymous modules, and avoid setting a global if an
    // AMD loader is present. jQuery is a special case. For more information, see
    // https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
    
    if ( typeof define === "function" && define.amd ) {
        define( "jquery", [], function() {
            return jQuery;
        } );
    }