jQuery.ui undefined after requirejs optimization - javascript

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 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.
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 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.

Related

Using shim config with almond

I am trying to shim certain modules for usage with almond like so:
<script>
requirejs.config({
shim: {
'jQuery': { exports: 'jQuery' },
//etc.
</script>
as certain scripts will already be included. However, this code:
require(['jQuery', function($) {
});
results in "undefined missing jQuery". If I shim jQuery like this:
define('jQuery', function() {
return jQuery;
});
it works.
I am not building my JS at all, just dropping almond.js into an existing web software so I can develop my new components with AMD. I would like to shim existing globals for my new modules.
I am guessing shims are only resolved on build and that the build does exactly what I am doing above, is that correct?
The name for jQuery is hard-coded to "jquery". If you deviate from this you'll run into trouble. But that's not your only problem.
Using shim is not the same as calling define with a module name. When you use shim like you do in your question you tell the loader that there exist a module with the name jQuery and that once that module is loaded, RequireJS should return as a module value the value of the variable jQuery. The emphasized text is important: the loader will fetch and load a module named jQuery.
The define you show in your question would usually be placed together with the call to require.config, either just before it or just after it. This declares a module named jQuery. Because the module is already there, when the loader needs to get this module, there is nothing to fetch. This is an important difference when it comes to Almond.
Almond has restrictions, one of them is:
optimize all the modules into one file -- no dynamic code loading.
(Emphasis added.) Using the terms I've used in this answer this means "no fetching". When you use your define call, you are fine. When you use the shim, then unless you optimized your modules into one file, the loader has to try fetching the module. Almond cannot do that.

TypeError: require.config is not a function

I am using require.js as part of a brunch project. This code is throwing the error:
;require.config({ // require.config is not a function
paths: {
jquery: "lib/jquery",
underscore: "lib/underscore",
backbone: "lib/backbone",
localstorage: "lib/backbone.localStorage"
}
});
Does that mean that requirejs is not getting included properly in the project?
If you get that error, it could be that:
RequireJS is not loaded.
This can diagnosed by opening the browser's debugger to look at network requests and seeing whether the file that defines require is asked by the browser and checking that the response indicates that the data is available (i.e. loaded from the server, loaded from cache).
RequireJS is loaded but not initializing properly.
This could happen if something is loaded before RequireJS and somehow messes with the JavaScript runtime in a way that makes RequireJS fail to initialize. For instance, if something puts in the global space a global named define of any type, or global named requirejs and which is a function, then RequireJS will silently abandon initializing.
I'd diagnose this with breakpoints in the file that contains RequireJS to see whether it completes execution or not.
RequireJS is loaded but something else redefines require.
I'd inspect the value of require just after RequireJS is loaded. If it has a config method defined at that point, then something else must be messing with it later.

Require.js 3rd Party Library Dependencies

What is the benefit of defining 3rd party libraries (JQuery/Underscore/Backbone) as modules and using those as dependencies?
require(["jquery", "underscore"], function($, _) {
// Use $ and _ in here
});
Underscore for example creates a global '_' variable, that I could just as easily use within the function above, assuming underscore is included prior to that function.
To be used by Require, Underscore requires the code to be modified to return a value, or a shim defined. Why bother, when I can just include it via a script tag?
I get that it provides a certain level of indirection and allows me to map other dependencies to those same variables, and have it scoped locally to that function. However, I don't see this ever being useful for these types of 3rd party libraries that form the core of the application.
After building some apps with Backbone/requireJs I can see no disadvantage in building a backbone app with requireJs, where the main dependencies are simple loaded via an old school script tag.
You have to load this requirements anyway in the first place, its used by the most of your modules and you will probably never exchange it with another framework. So there is no afford for the boilerplate code in every module.
You don't have to change the library to use it in AMD loader.
require.config({paths:{underscore:'//some.cdn/path/to/underscore.js'}})
require(["jquery", "underscore"], function($ /*, note that we don't override _ here */) {
// Use AMD $ and global _ in here
});

Require.js is hurting my brain. Some fundamental questions about the way it loads scripts/modules

Let's assume this is my config.js or main.js:
require.config({
// paths are analogous to old-school <script> tags, in order to reference js scripts
paths: {
jquery: "libs/jquery-1.7.2.min",
underscore: "libs/underscore-min",
backbone: "libs/backbone-min",
jquerymobile: "libs/jquery.mobile-1.1.0.min",
jquerymobilerouter: "libs/jquery.mobile.router.min"
},
// configure dependencies and export value aliases for old-school js scripts
shim: {
jquery: ["require"],
underscore: {
deps: ["jquery"],
exports: "_"
},
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
},
jquerymobilerouter: ["jquery", "backbone", "underscore"],
jquerymobile: ["jquery", "jquerymobilerouter", "backbone", "underscore"]
}
});
require(["jquery", "backbone", "underscore", "app/app.min", "jquerymobilerouter", "jquerymobile"], function ($, Backbone, _, App) {
console.log($);
console.log(Backbone);
console.log(_);
$("body").fadeIn(function () {
App.init();
});
});
If I understand correctly, the paths config option allows you to reference scripts, a-la the <script> tag within HTML. Assuming this is the case, do I still need to alias scripts like jQuery with a $ or underscore with a _ in my actual require statement below? It seems strange that I'd have to, given that if you reference jQuery with a standard <script> tag, $ can be used throughout your script automatically. Shouldn't it be the same using the paths?
I'm new to the shim config option, which I understand has replaced the deprecated order! plugin. What does the exports property actually DO? It doesn't seem to create an alias for a script; for example, if I set the exports for underscore to "whatever", and then try to console.log(whatever), it's undefined. So what's the point?
How would scripts like jQuery be properly used "globally?" That is, what's the proper way to be able to use the $ alias within my App.js module, or any other module in my "app" folder? Do I have to require jQuery within every individual module and alias $ every single time? Or is the way I've done it here the proper way?
I'd greatly appreciate any other criticisms of this particular script as well; the documentation for Require.js, in my opinion, leaves much to be desired; things I'd really like to know more about seem to get glossed over and leave me scratching my head.
Just to clear up any confusion around exports, it's assumed that any shim library attaches a property to the global context (window or root), or modifies an already-existing global property (e.g. a jQuery plugin). When requireJS gets the command to load a shimmed dependency, it examines the global context for a property matching the exports value of that shim config, and if it finds it, returns it as the value of that module. If it doesn't find it, then it loads the associated script, waits for it to execute, then finds the global symbol and returns it.
An important fact to remember is that unless the shim config contains an exports value, any init method on that config will NOT be executed. The dependency loader must locate a value for the module (which is what exports specifies) before that module can be initialized, which is why the property is required if there is a shim init for that module.
update: I also need to point out that if the module in question calls define anywhere, any shim config you have for that module will be ignored. This actually caused me some headaches because I wanted to use the shim config to call jQuery's jQuery.noConflict(true) method to un-globify jQuery and keep it scoped to just the modules that require it, but couldn't manage to get it working. (See update at bottom for info on how to easily do this using map config instead of shim config.)
update 2: A recent question on the requireJS google group made me realize that my explanation might be slightly misleading, so I'd like to clarify. RequireJS will only re-use a shimmed dependency if it was loaded via requireJS at least once. That is to say, if you simply have a <script> tag on the hosting page (say, for example, underscore), like this:
<script src='lib/underscore.js'></script>
<script src='lib/require.js' data-main='main.js'></script>
...and you have something like this in your requireJS config:
paths: {
'underscore': 'lib/underscore'
},
shim: {
'underscore': {
exports: '_'
}
}
Then the first time you do define(['underscore'], function (_) {}); or var _ = require('underscore');, RequireJS will re-load the underscore library rather than re-using the previously defined window._, because as far as requireJS knows, you never loaded underscore before. Sure, it can check to see if _ is already defined on the root scope, but it has no way of verifying that the _ that's already there is the same as the one defined in your paths config. For example, both prototype and jquery assign themselves to window.$ by default, and if requireJS assumes that 'window.$' is jQuery when it is in fact prototype, you're going to be in a bad situation.
All of that means that if you mix-and-match script loading styles like that, your page will wind up with something like this:
<script src='lib/underscore.js'></script>
<script src='lib/require.js' data-main='main.js'></script>
<script src='lib/underscore.js'></script>
Where the second underscore instance is the one loaded by requireJS.
Basically, a library has to be loaded via requireJS for requireJS to have knowledge of it. However, the next time you require underscore, requireJS will go "hey, I already loaded that, so just hand back whatever the exports value is and don't worry about loading another script."
This means you have two real options. One is what I would consider an anti-pattern: simply don't use requireJS to express dependencies for global scripts. That is, as long as a library attaches a global to the root context, you'll be able to access it, event if that dependency isn't explicitly required. You can see why this is an anti-pattern - you've basically just eliminated most of the advantages to using an AMD loader (explicit dependency listing and portability).
The other, better option is using requireJS to load everything, to the degree that the only actual script tag you should create yourself is the one that initially loads requireJS. You can use shims, but 95% of the time it's really not that difficult to add an AMD wrapper to the script instead. It might take a little more work to convert all of your non-AMD libraries to be AMD compatible, but once you've done one or two it gets a lot easier - I can take any generic jQuery plugin and convert it to an AMD module in less than a minute. It's usually just a matter of adding
define(['jquery'], function (jQuery) {
at the top, and
return jQuery;
});
at the bottom. The reason I have 'jquery' mapping to jQuery rather than $ is that I've noticed most plugins these days are wrapped in a closure like this:
(function ($) {
// plugin code here
})(jQuery);
And it's a good idea to pay attention to the intended scope. You can certainly map 'jquery' to $ directly though, assuming the plugin isn't expecting to find jQuery instead of $. That's just the basic AMD wrapper - more complex ones generally try to detect what kind of loader is being used (commonJS vs AMD vs regular ol' globals) and use a different loading method depending on the result. You can find examples of this pretty easily with a few seconds on google.
Update: The workaround I used to support using jQuery.noConflict(true) with RequireJS worked, but it required a very small modification to the jQuery source, and I have since figured out a much better way to accomplish the same thing without modifying jQuery. Luckily enough, so has James Burke, the author of RequireJS, who has added it to the RequireJS documentation: http://requirejs.org/docs/jquery.html#noconflictmap
Paths tell require.js where to look when you require that dependency.
For example i have things configured like this:
"paths": {
"jquery": "require_jquery"
},
"shim": {
"jquery-cookie" : ["jquery"],
"bootstrap-tab" : ["jquery"],
"bootstrap-modal": ["jquery"],
"bootstrap-alert": ["jquery"]
},
this means that every time in a module I do
define( ['jquery']
requirejs loads the file require_jquery from the main path instead of trying to load jquery.js. In your case it would load the jQuery source file, which would then be globally available. I personally don't like that approach and for that reason in the require_jquery.js file I do:
define( ["jquery_1.7.2"], function() {
// Raw jQuery does not return anything, so return it explicitly here.
return jQuery.noConflict( true );
} );
which means that jQuery will be defined only inside my modules. (This is because i write Wordpress plugins and so I can include my own version of jQuery without touching the outside version)
Exports (reading from the docs simply should be the name of the module you are using so that it can be detected if loading went correctly. Here is explained. So if you want to set an export for underscore it should be _
jQuery should be global as I explained, if you simply import it the file is executed and jQuery is global
EDIT - to answer the comments.
yes i mean that, you must export $ or jQuery for jQuery and _ for backbone. From what i got from the docs this is needed only in some edge cases and would not be necessary for libraries that declare themselves in the global namespace as jQuery.
I think that requirejs needs them when it has to fallback from loading jQuery from a CDN. i think that requirejs first tries to load jQuery from the CDN, then makes a check to verify that it was loaded correctly by checking that the "exported" variable exists, and if it doesn't it loads it form the local filesystem (if you had configured fallbacks, of course). This is something that it's needed when requirejs can't see a 404 coming back.
jQuery is globally available because it's declared global. If you simply load and execute the jQuery script, you will end up with two globals, $ and jQuery (or you can do as i did and avoid that). Inside the define() function you can alias jQuery to be whatever you want.
define( [ 'jquery' ], function( jq ) {
// jq is jquery inside this function. if you declared it
// globally it will be also available as $ and jQuery
} );

Node.js require() vs RequireJS?

Hello with RequireJS I can set a base path like this: base : './app/' so when I am in ./app/foo/bar/ for example and I have a script where I use require('foo'); RequireJS then would search for ./app/foo.js and not in node_module folder or in ./app/foo/bar/foo.js this comes handy when you have a kind of structure where it would be much cleaner for you as a developer to see the dependencies instead of having ../../foo.js. I could have ./app/foo.js and ./app/foo/foo.js and ./app/foo/bar/foo.js it would be much more cleaner to have:
require('foo');
require('foo/foo');
require('foo/bar/foo');
rather than:
require('../../foo');
require('../foo');
require('./foo');
Now you could say why not change the name and not have foo everywhere, let's say that we can't for any reason…
Another lack of feature that I see in node's require method against RequireJS is the ability of setting path mapping, if I have a directory named ./app/super-sized-directory-name/ in RequireJS I could simply do 'big-dir' : 'super-sized-directory-name' and then I could simply use require('./app/big-dir/foo') with Node.js's require method this is not possible as far as I know…
--alias, -a Register an alias with a colon separator: "to:from"
Example: --alias 'jquery:jquery-browserify'
You can register aliases with browserify, so that covers your renaming.
As for your rooted absolute paths, that can't really be done. As mentioned modul8 has a namespacing mechanism to solve this.
I would recommend you pong SubStack in #stackvm on freenode and ask him directly.
It may or may not help you, but I believe the Dojo Frameworks AMD Loader is API compatible with RequireJS and providing you are using a new microkernel does not pollute the global namespace.
I believe it only has require() and define() in the global namespace now.
Anyway their method of dealing with this is to do something like:
require(["dojo/node!util"], function(util){
// Module available as util
});
The documentation is at http://dojotoolkit.org/reference-guide/1.8/dojo/node.html
Use uRequire which provides a 'bridge' between nodejs require and AMD define modules, without reinventing the wheel (it is build on top of the two standards). It basically converts modules from AMD or commonJS format to the other format or UMD that runs smoothly on both nodejs & the browser.
It is also translating dependency paths with flexible path conventions, so you can have either '../../foo' or 'bar/foo' depending on which makes more sense at the point you are at.
Your AMD or UMD modules are loaded asynchronously on browser (using AMD/requireJs or other AMD loader) and on node the asynchronous require(['dep1', 'dep2'], function(dep1,dep2){...}) is also simulated.

Categories