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?
Set the dependencies between non-AMD modules using shim
rather than through nested require
calls (which do not in fact set dependencies). Make sure also to use wrapShim: true
in the configuration you give r.js
.
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 require
calls 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 define
call. 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 a define
call with an array of dependencies. So it does not constitute a 3rd way.)
By setting a shim
which 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-punch
could appear before jquery-ui
and jquery
in 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 wrapShim
because the jquery-ui.touch-punch
when using an AMD-aware version of jQuery UI. Otherwise, jQuery UI's factory won't be run before the plugin needs it.