gerald gerald - 4 months ago 21
Javascript Question

RequireJS + Backbone + jQuery loaded through `script` interfering with jQuery loaded through RequireJS

I just tried upgrading to Backbone 1.1.2, and have been having issues with jQuery.

By default, Backbone expects to find the jQuery in the base directory as

./jquery.js
. When I add this into the RequireJS path and add it to the shim as a dependency for Backbone, then everything works inside of
require
, but outside, nothing works. It's as if the local reference I am creating is stomping over the globally included jQuery?

In my html page, I have this:

<script src="js/lib/jquery/2.0.2/jquery.min.js"></script>
<script src="js/lib/jqueryui/{$jquery.ui.version}/jquery-ui.min.js"></script>
<script data-main="js/homepage" src="js/lib/require/2.1.11/require.min.js"></script>


homepage.js
(which currently works) looks like this:

require.config({
baseUrl: "./js",
paths: {
Underscore: 'lib/underscore/1.6.0/underscore-min',
Backbone: 'lib/backbone/1.0.0/backbone-min'
// ,jquery: 'lib/jquery/2.0.2/jquery.min'
// ,jqueryui: 'lib/jqueryui/1.10.3/jquery-ui.min'

},

shim: {
// 'jqueryui': {
// deps: ['jquery'],
// exports: "$"
// },
'Underscore': {
// deps: ['jquery'],
exports: "_"
},
'Backbone': {
deps: ['Underscore', /*'jquery'*/],
exports: 'Backbone'
}

}

});

require([ 'views/homepage/main' ], function(Main) {

});


In this situation, I am using the global jQuery and it works perfectly, both inside the app, and globally for my site navigation which uses jQuery. The js also minifies perfectly with
r.js
.

But when I change my BB version to 1.1.2, it says that it can't find
jquery.js
. When I uncomment all of the lines in
homepage.js
to include jQuery dependencies, everything renders within the application, but now my navigation breaks, saying that the jQuery functions that i have created are undefined. I am also unable to minify my app in
r.js
.

This leads me to believe that
jQuery
and
$
in the global namespace are being stomped on when RequireJS starts downloading its dependencies. Is this just a classic case of needing to use
$.noConflict
? If so, how do I modify my code to do this?

Answer

Update for more recent versions

The answer was originally written for Backbone 1.1.2, and an older version of Underscore.

Recent versions are AMD-aware and do not need shim set for them. You should also use all lowercase names for the modules: backbone and underscore because some of these names are hardcoded. (You can work around the hardcoding with a map config but it is just simpler to use the standard, all lowercase names.)

The solution

If you load jQuery with a <script> tag and then load it in RequireJS you have to take special precautions. However, I do not notice anything in your question that indicates that you need to have two jQueries loaded. So you could use the following trick to use the same instance of jQuery outside and inside AMD modules:

define('jquery', [], function () {
    return jQuery;
});

require.config({
    baseUrl: "./js",
    paths: {
        Underscore: 'lib/underscore/1.6.0/underscore-min',
        Backbone: 'lib/backbone/1.1.2/backbone-min'
    },

    shim: {
        Underscore: {
             exports: "_"
        }
    }

});

require([ 'views/homepage/main' ], function(Main) {

});

This way when RequireJS "loads" the jquery module, it'll execute the code passed to the define above. As I recall, jQuery UI just installs itself as a jQuery plugin so you don't need to do anything special about it. Also I recommend using Backbone 1.1.2, which does not need a shim. Underscore does not depend on jQuery so the shim for it does not need a dependency for it.

Comments