RequireJS jQuery plugin shim not working? - javascript

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;
});

Related

Use jquery,backbone,underscore using requirejs globally?

I tried with following code to include my custom js file using require js
require.config({
waitSeconds: 0,
paths: {
underscore: 'underscore/underscore',
backbone: "backbone/backbone-min",
jquery: "jquery/jquery-min",
customhandler: "jquery/customhandler"
},
shim: {
underscore: {
deps: ['underscore'],
exports: '_'
}
}
});
Created separate file customhandler.js and inside i want to use backbone,jquery,underscore
define(['jquery','underscore','backbone'], function($,_,Backbone) {
//using jquery
var oldAjax = $.ajax;
$.ajax = function(options) {
console.log(options)
// Do your magic.
return oldAjax.apply($, arguments);
}
//need to use backbone,underscore here
});
But still i could not get it loaded into my application.Please advise.
jQuery is already AMD compatible, so looks like you can't shim this dependency in this way.
From official documentation:
http://requirejs.org/docs/api.html#config-shim
Remember: only use shim config for non-AMD scripts...
As a primitive workaround you could return another object like that:
return { ajax : $.ajax };
Or make it smarter if needed.
Modules that call define do not need to use shim. If you do use shim with a module that calls define you get undefined behavior. So this could be the reason you are getting problems: remove your shim for jqueryajaxhandler.

RequireJS not loading module properly [duplicate]

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.

Unable to load crossroads.js using RequireJS

I try to load JS files using RequireJS , however crossroads http://millermedeiros.github.io/crossroads.js/ seems not be loaded properly. I have checked using Chrome Dev Toolbar and all JS files are actually loaded. However running window.crossroad returned me undefined?
Below is my requirejs config.. Kindly advice... Thanks!
index.html
<script data-main="scripts/config" src="scripts/require.js"></script>
config.js
require.config({
shim: {
"zepto.min": {
exports: "$"
},
"underscore.min": {
exports: "_"
},
"crossroads.min": {
exports: "crossroads"
} }
});
require(["zepto.min","underscore.min", "crossroads.min",], function() {
console.log("=> Loading app")
require(["main"]);
});
main.js
require(["hp-config", "hp-model", "hp-view", "hp-controller"], function () {
console.log("=> Init");
console.log(window.crossroads);
//$(document).ready( function(){ HP.C.init(); });
});
If you look at the code for crossroads, you'll see that it detects that it is in a AMD environment (which RequireJS is) and calls define by itself. So you should remove the shim you have for it. The basic rule is: a library that does not call define needs a shim but a library that calls define does not. The reason window.crossroads is undefined is that crossroads calls define instead of exporting itself in the global space (on window).
Given the require.config call you currently have, the updated call would be:
require.config({
shim: {
"zepto.min": {
exports: "$"
},
"underscore.min": {
exports: "_"
}
}
});
The above config is the minimum change required. However, I would also advise not using .min in the names you pass to require or define. So your config.js could be instead:
require.config({
paths: {
zepto: "zepto.min",
underscore: "underscore.min",
crossroads: "crossroads.min"
},
shim: {
zepto: {
exports: "$"
},
underscore: {
exports: "_"
}
}
});
require(["zepto","underscore", "crossroads",], function() {
console.log("=> Loading app")
require(["main"]);
});
This way, if you want to switch to the non-minified version (for debugging) you can just change the paths setting instead of having to go everywhere you require these modules and change the names.

Using requirejs with Colorbox: Uncaught TypeError

So, after clicking on a button I want to display a Lightbox containing a link to youtube.
I use requirejs and lightbox in my project, but I get an error:
"Uncaught TypeError: Object function (e,t){return new x.fn.init(e,t,r)} has no method 'colorbox'"
I think the function doesn't find Colorbox, but I don't know why.
This is my file: openYoutubeLink:
define( [ 'modules/common/preferences' ], function ( preferences ) {
return function () {
$.colorbox({width:"900px", height:"600px", iframe:true, href:"youtube.de"});
};
});
Here a part of my main.js with the require.config:
paths: {
colorbox : 'libs/jquery/jquery.colorbox-min'
}
shim: {
'colorbox' : { deps: [ 'jquery' ], exports: 'jquery' }
}
I would make it so that the main module requires jQuery and the colorbox plugin. I'd require them so that I'm sure they are both loaded when my module executes. Currently, it looks like you have the global $ defined but this looks like happenstance rather than design.
So after modifications it would look like this:
define(['modules/common/preferences', 'jquery', 'colorbox'],
function (preferences, $) {
return function () {
$.colorbox({width:"900px", height:"600px", iframe:true, href:"youtube.de"});
};
});
Also, I do not believe this is the source of your immediate problem but I should mention that the exports here is wrong:
shim: {
'colorbox' : { deps: [ 'jquery' ], exports: 'jquery' }
}
You want to have a symbol which is specific to the module being shimmed. For instance, I use the cookie plugin for jQuery and shim it like this:
'jquery.cookie': {
deps: ["jquery"],
exports: "jQuery.cookie"
}
jQuery.cookie is a symbol which is defined if and only if the jquery.cookie file has loaded and executed properly.
(kryger suggested not defining exports. While it is true that the RequireJS documentation says that plugins like those of jQuery or Backbone don't need to have an exports defined, the same documentation then mentions that the detection of error conditions won't work if exports is not used. I consider the best practice to be always defining an exports rather than wait until eventual problems crop up.)

Using private jquery with RequireJS - issue after optimisation

I'm putting together a framework using requireJS with a CDN version of jQuery (as is now the recommended approach) and having some issue when optimizing the code. The output is namespaced and I'm specifying that each module use a private version of jquery as outlined in the documentation:
require.config({
// Add this map config in addition to any baseUrl or
// paths config you may already have in the project.
map: {
// '*' means all modules will get 'jquery-private'
// for their 'jquery' dependency.
'*': { 'jquery': 'jquery-private' },
// 'jquery-private' wants the real jQuery module
// though. If this line was not here, there would
// be an unresolvable cyclic dependency.
'jquery-private': { 'jquery': 'jquery' }
}
});
// and the 'jquery-private' module, in the
// jquery-private.js file:
define(['jquery'], function (jq) {
return jq.noConflict( true );
});
The problem I'm seeing after optimization is that "jq" is undefined in the "jquery-private.js" file.
Any ideas? I've tried setting jq = $ but that seems to destroy the global.
Thanks.
Here is what I did to get the jQuery CDN & optimization sample linked from the RequireJS jQuery Instructions page to work with the Mapping Modules to use noConflict section that you pasted in your original question.
1 - Forked the sample
2 - Created file www/js/lib/jquery-private.js with this content
define(['jquery'], function (jq) {
return jq.noConflict( true );
});
3 - Modified www/js/app.js to paste the map section so the require.config now looks like this:
requirejs.config({
"baseUrl": "js/lib",
"paths": {
"app": "../app",
"jquery": "//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min"
},
map: {
'*': { 'jquery': 'jquery-private' },
'jquery-private': { 'jquery': 'jquery' }
}
});
4 - Modified www/js/app/main.js to use jqlocal instead of $ (just to prove to myself that it's not the global jQuery:
define(["jquery", "jquery.alpha", "jquery.beta"], function(jqlocal) {
jqlocal(function() {
jqlocal('body').alpha().beta();
});
});
5 - Changed to the tools folder and ran:
node r.js -o build.js
6 - Changed to the www-build folder that was created and ran servedir (doesn't really matter what web server but that's what I use for dev)
7 - Browsed to the local address & port number of the app (in my case http://localhost:8000/app.html) and saw:
Alpha is Go!
Beta is Go!
You can see the end result here
To get this working I changed the way I was using Require (possibly how I should have been doing it all along). This information might prove useful to others, so I thought I'd put it out there.
Previously I was specifying any dependencies in the defined module:
define( [ "dep1", "dep2", "jquery" ], function( var1, var2, jq ) {
This worked fine initially, but failed when optimized. I moved the dependencies to the require function call including this module and it then started to work OK both pre and post optimisation, with jquery being used privately:
require( [ 'jquery', 'dep1', 'dep2' ], function( jq, var1, var2 ) {
formValidator.formValidationInit( jq( el ) );
});
I wouldn't have thought this would have made a difference, but it seemed too.
It is also worth noting that I had to change the jquery-private file as it was still throwing up an issue concerning "jq" not being defined. I am now setting jq equal to the global $ and returning it so it can be used pivately:
define(['jquery'], function () {
var jq = $;
return jq.noConflict( true );
});

Categories

Resources