I'm a RequireJS noob. When I use "require.config" and include a path to jQuery with a name different than jQuery, results are not as expected.
Here's a very simple example to help explain my issue.
Structure of files
root
├── Index.htm
└── scripts
├── libs
│ ├── jquery-1.7.1.js
│ └── require.js
├── main.js
└── someModule.js
index.htm
<html>
<head>
<title>BackboneJS Modular app with RequireJS</title>
<script data-main="scripts/main" src="scripts/libs/require.js"></script>
</head>
<body>
<h3>BackboneJS is awesome</h3>
</body>
</html>
Here the script tag references require in scripts/libs. When require gets ran the JavaScript file called main.js in the scripts directory should be executed.
main.js
require.config({
"paths": {
"mod1": "someModule"
}
});
require(["mod1"], function (sm) {
console.log(sm.someValue);
});
In my experience the "mod1" can be anything as long as it's referenced the same in the require.config path and in the require method.
someModule.js
define([], function () {
console.log();
return { someValue: "abcd" };
});
Just for completeness I included someModule.js
The perceived inconstancy occurs when I include JQuery.
In the following main.js I added jQuery to the config and the require method.
Main.js
require.config({
"paths": {
"jquery": "libs/jquery-1.7.1"
,"mod1": "someModule"
}
});
require(["mod1", "jquery"], function (sm, $) {
console.log(sm.someValue);
console.log($);
});
With the additional of jQuery everything seems to still works. The "console.log($)" writes the jQuery function.
Now the kicker. In the following code I change "jquery" to "jqueryA" in both the paths and require
require.config({
"paths": {
"jqueryA": "libs/jquery-1.7.1"
,"mod1": "someModule"
}
});
require(["mod1", "jqueryA"], function (sm, $) {
console.log(sm.someValue);
console.log($);
});
Now "console.log($)" writes null.
Should this be expected? Is there a reason why the name must be jquery, but for mod1 it can be anything?
I can work-around this without a problem, but this issue seems odd. I know I can use the combined RequireJS and jQuery file, but when jQuery has an update I don't want to be dependent on RequireJS to include the new jQuery.
In jQuery 1.7 they decided to support AMD loading. To do this, it defines a module named 'jquery' which passes back a reference to the jQuery object. When you define your path to jquery with another name (eg 'jqueryA'), things aren't exactly breaking as you think they are.
The jquery script always defines itself as a module named 'jquery', which is registered with require for your app. When you named your path shortcut 'jquery' and 'jquery' was loaded as a dependency, require was actually referencing the 'jquery' module defined by jquery-1.7.1.js, which does pass back the correct reference. When you name your module shortcut jqueryA, you are now referencing an undefined reference, because the jquery script itself does not pass back a reference, except via the module named 'jquery'. It's silly, I know.
The jquery script defines the module as 'jquery' and expects that you will simply reference it as 'jquery'. If you want to reference it as another name (and as a bonus, keep it from conflicting with other loaded jquery libraries), use this method:
Use requirejs and jquery, without clobbering global jquery?
Here's my workaround, based on the implementation I read of Require.JS 2.1.0:
define.amd.jQuery = false;
require.config({
...
shim: {
"jQuery-1.8.2": {
exports: "jQuery"
}
}
...
});
I believe I found the answer to my issue.
Optionally call AMD define() to register module
https://github.com/documentcloud/underscore/pull/338#issuecomment-3253751
Here's a quote from the previous link. Even though it pertains to underscore, I believe it relates to JQuery also.
all AMD loaders allow mapping a module ID to a partial
path, usually the configuration is called 'paths', so to do what you
want:
requirejs.config({
paths:
underscore: 'js/libs/underscore-1.2.3.min'
} }); require(['underscore'], function () {}); Since underscore is used by other higher-level modules, like backbone, a common dependency
name needs to be used to communicate a common dependency on
underscore, and it makes sense to call that dependency 'underscore'.
The paths config gives a way to do the mapping to a specific URL you
want to use for that dependency.
Here's a rant that does a very good job of describing the issues with AMD and named modules.
AMD modules with named defines. So much pain for what gain?
http://dvdotsenko.blogspot.com/2011/12/amd-modules-with-named-defines-so-much.html
Quote from the link above
If the only way to consume the module properly is to force the
end-developer to hard-code its name again in a config file, at the
consumption point, (in that respect only) why waste time, effort and
hard-code the name in the module in the first place (let alone cause
grief to those devs who DO need to load the module under different
name / from alternate sources)?
In this post James Burk recommends not using name module.
https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
Normally you should not register a named module, but instead register
as an anonymous module:
This allows users of your code to rename
your library to a name suitable for their project layout. It also
allows them to map your module to a dependency name that is used by
other libraries. For instance, Zepto.js can be mapped to fulfill the
module duty for the 'jquery' module ID.
There are some notable exceptions that do register as named modules:
•jQuery •underscore
Exception suck. Exceptions makes it difficult for noobs.