I have several JavaScript files in my web application which were previously loaded through <script> tags, in order of relative dependencies. Now I'm re-organizing them through require.js in order to accumulate and minify them for production.
For starters, I'd like to simply load all files into the global (window) context, without AMD encapsulation yet:
require([
'jquery'], function() {
require([
'jquery-ui'], function() {
require([
'jquery-ui.touch-punch',
// [...]
]);
});
});
The idea here is that 'jquery' defines a global (window context) jQuery variable, 'jquery-ui' sets jQuery.ui and 'jquery-ui.touch-punch' alters jQuery.ui (for better touch support).
This works well when running as is, i.e. without optimization. However, after compiling into one file and minifying using the RequireJS optimizer, the following error occurs:
Uncaught TypeError: Cannot read property 'mouse' of undefined
This happens on a line trying to access jQuery.ui.mouse.
Inside the browser console, jQuery is correctly set in the window context, but jQuery.ui is undefined.
However, manually executing require(['jquery-ui']) does set jQuery.ui as expected.
It seems like jQuery UI behaves differently after optimization, but I can't see how exactly or why. What am I doing wrong?
The Scoop
Set the dependencies between non-AMD modules using
shimrather than through nestedrequirecalls (which do not in fact set dependencies). Make sure also to usewrapShim: truein the configuration you giver.js.Explanation
One or more of the modules you are trying to load are not AMD modules, but you are not actually defining dependencies between your non-AMD modules.
When you nest
requirecalls like you do, you are coercing the order in which some modules are loaded at run time, but this does not actually establish a dependency between modules. So this strategy works as long as the modules are not optimized but may fail after optimization.There are only two ways to establish dependencies:
By passing an array of dependencies to a
definecall. This method is used by modules actually written for the AMD spec. (RequireJS also supports using the CommonJS way of requiring modules but behind the scenes, it is transformed to adefinecall with an array of dependencies. So it does not constitute a 3rd way.)By setting a
shimwhich list dependencies. This method is for non-AMD modules.If you don't set a
shim, then the optimizer is free to order the non-AMD modules in whichever order it wants.jquery-ui.touch-punchcould appear beforejquery-uiandjqueryin the optimized file, because there's no reason it shouldn't, and then you'd run into trouble. If you look at the code of this plugin, you see that it is not AMD-aware. It just expects jQuery and jQuery UI to be present and will fail if they are not present.When you do set a
shim, then you coerce the order of the non-AMD modules in the optimized file.You need
wrapShimbecause thejquery-ui.touch-punchwhen using an AMD-aware version of jQuery UI. Otherwise, jQuery UI's factory won't be run before the plugin needs it.