I am attempting to get started with RequireJS, and am running into an annoying issue. . .
require.config({
baseUrl: 'app_content/scripts',
paths: {
// the left side is the module ID,
// the right side is the path to
// the jQuery file, relative to baseUrl.
// Also, the path should NOT include
// the '.js' file extension. This example
// is using jQuery 1.9.0 located at
// js/lib/jquery-1.9.0.js, relative to
// the HTML page.
'jQuery': 'lib/jQuery/jQuery-2.0.3'
}
});
This, using uppercase Q, does not work, But if I change it to jquery, it does. Also, this is true in my required areas...
<script type="text/javascript">
require(["jQuery"], function ($) {
console.log($);
});
</script>
This returns undefined, but if I change everything to straight up jquery, it works.
Is this expected behavior, and is there anything I can do about it?
Yes, jQuery defines itself as 'jquery', all lowercase. That's normal.
If you open the source to jQuery you'll find:
// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function () { return jQuery; } );
}
So you have to refer to it as "jquery" everywhere in RequireJS calls. The issue here is that the define that jQuery uses is a "named define" which is something we normally do not use when creating modules. The RequireJS optimizer adds these names for us when we run it.
At any rate, when a "named define" is used the module name is set to the name given to define rather than by file names (as is otherwise the case when we don't use a named define).
It is possible to rename "jquery" to "jQuery", like this:
require.config({
baseUrl: "./js",
paths: {
"jquery": "jquery-1.10.2"
}
});
define("jQuery", ["jquery"], function ($) {
return $;
});
require(["jQuery"], function ($) {
console.log($);
console.log($("body")[0]);
});
I'm making use of the version of define that takes a name as the first parameter. Full example here.
Related
It seems that recent versions of Backbone.js and Underscore.js support AMD.
So am I correct in assuming that it is no longer needed to "shim" these libraries in the require.js configuration?
Yes, you are correct, no shim needed. And it's easy to test, here's the simplest setup:
requirejs.config({
/**
* Paths to lib dependencies.
*
* Use non-minified files where possible as they will be minified (and
* optimized via uglify) on release build (r.js)
*/
paths: {
"jquery": "libs/jquery/dist/jquery",
"underscore": "libs/underscore/underscore",
"backbone": "libs/backbone/backbone",
},
deps: ["app"] // starts the app
});
And to make sure it works and it's not the global Underscore that's used:
// I'm using Underscore as to avoid conflicting with the global _
// but you could use _ as the name for the local variable as well.
define(['backbone', 'underscore'], function(Backbone, Underscore) {
console.log("Backbone:", Backbone.VERSION)
console.log("Local Underscore:", Underscore.VERSION);
console.log("Global Underscore:", _.VERSION, _ === Underscore);
});
For Backbone, it's clear in the source that it supports AMD by default:
// Set up Backbone appropriately for the environment. Start with AMD.
if (typeof define === 'function' && define.amd) {
define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
// Export global even in AMD case in case this script is loaded with
// others that may still expect a global Backbone.
root.Backbone = factory(root, exports, _, $);
});
As for Underscore, it is registering itself at the end:
// AMD registration happens at the end for compatibility with AMD loaders
// that may not enforce next-turn semantics on modules. Even though general
// practice for AMD registration is to be anonymous, underscore registers
// as a named module because, like jQuery, it is a base library that is
// popular enough to be bundled in a third party lib, but not be part of
// an AMD load request. Those cases could generate an error when an
// anonymous define() is called outside of a loader request.
if (typeof define === 'function' && define.amd) {
define('underscore', [], function() {
return _;
});
}
Same thing with jQuery:
// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
// Note that for maximum portability, libraries that are not jQuery should
// declare themselves as anonymous modules, and avoid setting a global if an
// AMD loader is present. jQuery is a special case. For more information, see
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
} );
}
As #ggozad mentioned:
Well, if underscore is already loaded and available, you do not need
the shim at all. Backbone will happily load. If not, it's probably
because underscore is not actually loaded.
It sounds however wrong to be only partially using require.js, you
might as well AMD-load them all.
I guess that explain why you don't need to load it using require.js
I'm using a cloud service called Parse in a JavaScript closure injected with require.js:
define([/*some dependencies*/],
function(/*some dependencies*/) {
...
// using Parse. For example:
var TestObject = Parse.Object.extend("TestObject");
...
}
The tutorial for using Parse in Javascript instructs to include their script in the HTML header:
<script src="//www.parsecdn.com/js/parse-1.4.2.min.js"></script>
I don't want the HTML page to depend on Parse and I don't want to clutter the HTML with external scripts. Instead, I would like to require parse-1.4.2.min.js directly from the script. What's the proper way of doing so? How do I define this dependency and make it work?
Similar to jQuery, Parse adds itself to the global scope on load. If no other scripts depend on it, it can simply be included as a dependency in a module or require call.
require([
'https://www.parsecdn.com/js/parse-1.4.2.min.js',
], function () {
console.log(Parse);
}
If you are using any other non-AMD scripts that depend on Parse (or any other library) you will need to use a config/shim. It tells requireJS what order it should load the scripts, based on their dependencies.
E.g. when using a jQuery plugin, you wouldn't want it to load and execute before jQuery itself.
A config/paths setup also helps organise your project by allowing script locations to be defined in a single location and then included by reference.
See the requireJS docs for more info.
The following config/require successfully loads Parse and a fictional plugin:
require.config({
// define paths to be loaded, allows locations to be maintained in one place
paths: {
parse: 'https://www.parsecdn.com/js/parse-1.4.2.min',
plugin: 'example-non-amd-parse-plugin.js'
},
// define any non-amd libraries and their dependancies
shim: {
parse: {
exports: 'Parse'
},
plugin: {
exports: 'plugin',
deps: ['parse']
}
}
});
require(['parse'], function(Parse){
console.log(Parse);
});
// note Parse is not required
require(['plugin'], function(plugin){
// Parse is available as it is depended on by plugin and on the global scope
console.log(Parse, plugin);
});
So after all I just wrote this and it seems to work. Don't know what the problem was in the first place...
define(["https://www.parsecdn.com/js/parse-1.4.2.min.js"],
function () {
I'm trying to get a jQuery plugin working properly with RequireJS, when using jQuery in the noconflict/noglobal state to force all modules to indicate whether they require jQuery. However, for non-AMD-friendly plugins, the shim config seems to not be working. Namely, if a jQuery plugin is defined with a wrapper like:
(function($) {
$.extend($.myPlugin, { myPlugin: { version:'0.0.1'} });
})(jQuery);
Then the following RequireJS configuration isn't working:
requirejs.config({
paths: {
jquery: ['//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min', 'jquery-min'],
},
map: {
'*': { 'jquery': 'jquery-noglobal' }, // Force all modules to use the non-global jQuery...
'jquery-noglobal': { 'jquery': 'jquery' } // ...except the wrapper module itself, which needs the real one.
},
shim: {
'sadPlugin': {
deps: ['jquery']
}
}
});
jquery-noglobal.js:
define(['jquery'], function(jq) {
return jq.noConflict( true );
});
The error that fires when the plugin code runs is: "can't call extend on undefined", meaning jQuery was never set at the outer level, so $ is undefined inside the self-executing function. I put breakpoints outside the plugin self-executing function, and inside to verify that.
I'm guessing part of the problem is capitalization; the module was written to expect jQuery (camelCase), while the AMD module name is jquery (lower case). Is there any way in the shim config to specify what the injected requirements' variable names should be?
I've also tried adding a sadPlugin: {'jquery':'jquery'} entry to the map hash, hoping to make shim give that module the global jQuery instead of the non-global one, but still jQuery/$ aren't defined by the time the function gets called.
EDIT: Found one kludge that does answer part of the problem: according to the comment found here, the deps of a shim need to be the full file path of the script to load, and cannot be an alias from the paths configuration.
So, since my CDN-fallback file of jQuery is jquery-min.js, if I do:
shim: {
'sadPlugin': {
deps: ['jquery-min']
}
}
The plugin works! However, since the "real" jQuery is now being used, it pollutes the global namespace, and the $ variable is then available without require()ing it, so defeats the whole purpose of the noglobal wrapper...
Just use
return jQuery.noConflict( true );
instead of
return jq.noConflict( true );
So, as local variable inside requirejs, your plugins can use the variable jQuery for the parameter $
(function($) {$.extend($.myPlugin, { myPlugin: { version:'0.0.1'} });})(jQuery);
The config that work for me is:
-- main.js
-- jquery-private.js
In main.js file:
require.config({
paths: {
},
map: {
'*': { 'jquery': 'jquery-private' },
'jquery-private': { 'jquery': '//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js' }
},
shim: {
myplugins: ['jquery']
}
});
In jquery-private.js file:
define(['jquery'], function () {
jQuery = $.noConflict(true);
return jQuery;
});
I have an add-on to an application (call it appX) that allows users to create their own customizations using javascript, css and appX's webservices api.
Usually customizations are small and do not involve a lot of external libraries/plugins but when they do have external libs the typical users' library of choice is jQuery.
In the next version of appX they are using jQuery natively which I know is going to break some of the customizations.
So I have a need to modularize this situation. I have some other problems that are coming up and RequireJS seems like a good solution to these issues. I just need to figure out how to apply RequireJS properly for this situation
In my POC I'm loading require.js as follows:
<!--A bunch of other script including jQuery (but not require) are loaded already -->
<script type="text/javascript" src="/custom/js/require.js"></script>
<script type="text/javascript" src="/custom/js/dostuff.js"></script>
We'll call the jQuery loaded with appX jqueryx and the one I want to load jqueryp (p for private)
jQuery utilizes AMD and by default uses this definition internally:
define( "jquery", [], function () { return jQuery; } );
But in this case RequireJS is loaded AFTER jQuery (jqueryx) so there will be no default 'jquery' definition correct?
Some more background before I show you my problem... the file structure is like this:
appx
/js:
jqueryx.js
other.js
appx
/custom/js:
jqueryp.js
dostuff.js
Looking at the RequireJS api it seems that I should be doing something like this:
require.config({
baseUrl : 'custom/js',
paths : { 'jquery' : 'jqueryp'},
map: {
'*': { 'jquery': 'jquery-private' },
'jquery-private': { 'jquery': 'jquery' }
}
});
define(['jquery'], function (jq) {
return jq.noConflict( true );
});
require(['jquery'], function(jq){
console.log(jq.fn.jquery);
});
But when I do this I get an error:
Mismatched anonymous define() module: function (jq)...
I've played around with switching references to jquery, jquery-private as it's kind of confusing but with no progress.
How should I be applying RequireJS to this situation?
Almost a year late but better than no answer at all...
The following part should be moved into a "jquery-private.js" file:
define(['jquery'], function (jq) {
return jq.noConflict( true );
});
You can't define a module in your main entry point. Even if you could, the module has no name so how would you reference it?
I have 3 JS libraries that I use that are in their own separate files. They are commented with the code minified in each individual file
file 1: http://jsfiddle.net/NGMVa/
file 2: http://jsfiddle.net/AzEME/
file 3: http://jsfiddle.net/qVkhn/
Now individually they work fine in my app, don't throw any errors. But I wanted to load less files so I combined them into one file like this: http://jsfiddle.net/Gxswy/
However, in Chrome it throws an error on the last line of the file:
Uncaught TypeError: undefined is not a function
and it then it doesn't work anymore. I didn't change anything in the code before I combined them, I just copy and pasted the content of the first 3 files into the new one, and it doesn't work anymore. Don't understand why combining them into one file seems to break functionality
Was hoping someone would have an idea what's going here?
Make sure to add the semicolons at the end of each file or concatenate and then minify and minifier should take care of that.
Try this code: https://gist.github.com/elclanrs/4728677
Reason
In my case it was because I specified dependencies in requirejs's shim, for a library (perfect-scrollbar) that already supports AMD loading. The result is that the whole of its code in define is bypassed after grunt-contrib-requirejs did its job.
Basically, to concat requirejs files together, grunt-contrib-requirejs would
// change this:
define(['d3'],function(d3){...});
// into this:
define('d3', ['d3'],function(d3){...});
Whereas inside perfect-scrollbar, there's already
(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory); // <-------------------------- this part
// after minification would become:
// define('PerfectScrollbar', ['jquery'], factory);
} else if (typeof exports === 'object') {
factory(require('jquery')); // Node/CommonJS
} else {
factory(jQuery); // Browser globals
}
}(function ($) {
// perfect-scrollbar code here...
});
Which conflicted with what I specified in shim:
shim: {
"PerfectScrollbar": ['jquery', 'jquery.mousewheel']
}
Therefore when requirejs got to the part where PerfectScrollbar was really defined, it hopped over it, assuming that it has already done the job.
Solution
Don't specify dependencies in shim for libraries that already have AMD support.
Question
But what if I need to specify dependencies? I need jquery.mousewheel on top of the jquery it already specified in its code.
Answer
Require that file with proper require, and get its own dependencies right:
define(['perfect-scrollbar', 'jquery.mousewheel'], function(){...});
Either when the library you need has AMD support,
// inside jquery.mousewheel:
require(['jquery'], factory);
Or it doesn't
shim: {
"IDontSupportAMD": ['jquery']
}