javascriptjqueryrequirejsrequirejs-define

For no reasons, sometimes, jQuery won't load with require.js


I created an app.js files who have all my JS files included to manage dependencies and stuff with other modules.

Usually, it work very well, but sometimes, it crashes. There's my app.js file. All my "modules" files have jQuery as dependency in the "define" function.

require.config({
    baseUrl: 'js/', // '../Style%20Library/js/' pour Sharepoint
    paths: {
        jquery: 'vendor/jquery-1.11.2.min',
        jqueryui: 'vendor/jquery-ui',
        jrespond: 'vendor/jrespond-0.10',
        transit: 'vendor/jquery.transit.min',
        easing: 'vendor/jquery.easing.1.3',
        mainMenu: 'modules/main-menu',
        resBreakpoints: 'modules/resBreakpoints'
        [...]
    }
});

require(['jquery','resBreakpoints', 'transit'], function($, resBreakpoints, transit) {
    // Support aux vieux browser pour ne pas utiliser le plugin transition
    if(!Modernizr.csstransitions){ 
        $.fn.transition = $.fn.animate; 
    }
});

What can cause the crash? When it work, there's no errors in the console, but when it crash it show this error for many modules.

Uncaught ReferenceError: jQuery is not defined

When jQuery is not defined, jQuery and other files are all fully loaded, no errors on the network tab.

Thank you for your help!


Solution

  • jQuery and a number of other libraries -- some old and some just adamant to avoid modern conventions (coughBackbonecough) -- do not support module loaders of any sort. To load those with require, you need to use the shims feature and explicitly list the symbols which the module exports. You can see an example here, in my front-end template project and isolated below:

    require.config({
        shim: {
          jquery: {
            exports: '$'
          }
        }
      });
    

    Adding the shim tells require to load the module, then treat a global symbol as if it were the default export from the module.

    When using jQuery from you other code, make absolutely sure you either:

    For cleanliness, I prefer the former. With the shim given, you'll need to require('jquery') at the start of each module, not require('$') or anything like that. The name (key) of the shim is the module name from there out and doing var $ = require('jquery') will return the symbol you need.

    For readability and self-documentation, I prefer to use the library name as the shim name (jquery, underscore, lodash) and import it into the scope using the symbol ($ or _), rather than having a single-non-alnum-character module name. That's personal preference, I believe, but it's pretty clear what

    import $ from 'jquery';
    

    does.

    If you have jQuery plugins or use Twitter's Bootstrap, you may need to define other shims that depend on your new jQuery "module." These force jQuery to be loaded before the plugin, essentially listing out the dependency tree for require independently of the modules themselves. My Bootstrap example should work for jQuery plugins as well:

    shim: {
      bootstrap: {
        deps: ['jquery']
      }
    }
    

    This forces dependencies between the modules, allowing you to require the plugin and be assured the parents will have been loaded previously. Since jQuery and the like put their symbols into the global scope, you shouldn't need to set up any imports to the plugins, just make sure the library has been required before the plugin starts to load.