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?
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;
} );
}