I read the requirejs document from here API
requirejs.config({
shim: {
'backbone': {
//These script dependencies should be loaded before loading
//backbone.js
deps: ['underscore', 'jquery'],
//Once loaded, use the global 'Backbone' as the
//module value.
exports: 'Backbone'
},
'underscore': {
exports: '_'
},
'foo': {
deps: ['bar'],
exports: 'Foo',
init: function (bar) {
//Using a function allows you to call noConflict for
//libraries that support it, and do other cleanup.
//However, plugins for those libraries may still want
//a global. "this" for the function will be the global
//object. The dependencies will be passed in as
//function arguments. If this function returns a value,
//then that value is used as the module export value
//instead of the object found via the 'exports' string.
return this.Foo.noConflict();
}
}
}
});
but i am not getting shim part of it.
why should i use shim and how should i configure, can i get some more clarification
please can any one explain with example why and when should we use shim.
thanks.
A primary use of shim is with libraries that don't support AMD, but you need to manage their dependencies. For example, in the Backbone and Underscore example above: you know that Backbone requires Underscore, so suppose you wrote your code like this:
require(['underscore', 'backbone']
, function( Underscore, Backbone ) {
// do something with Backbone
}
RequireJS will kick off asynchronous requests for both Underscore and Backbone, but you don't know which one will come back first so it's possible that Backbone would try to do something with Underscore before it's loaded.
NOTE: this underscore/backbone example was written before both those libraries supported AMD. But the principle holds true for any libraries today that don't support AMD.
The "init" hook lets you do other advanced things, e.g. if a library would normally export two different things into the global namespace but you want to redefine them under a single namespace. Or, maybe you want to do some monkey patching on a methods in the library that you're loading.
More background:
Upgrading to RequireJS 2.0 gives some history on how the order plugin tried to solve this in the past.
See the "Loading Non-Modules" section of This article by Aaron Hardy for another good description.
As per RequireJS API documentation, shim lets you
Configure the dependencies, exports, and custom initialization for
older, traditional "browser globals" scripts that do not use define()
to declare the dependencies and set a module value.
- Configuring dependencies
Lets say you have 2 javascript modules(moduleA and moduleB) and one of them(moduleA) depends on the other(moduleB). Both of these are necessary for your own module so you specify the dependencies in require() or define()
require(['moduleA','moduleB'],function(A,B ) {
...
}
But since require itself follow AMD, you have no idea which one would be fetched early. This is where shim comes to rescue.
require.config({
shim:{
moduleA:{
deps:['moduleB']
}
}
})
This would make sure moduleB is always fetched before moduleA is loaded.
- Configuring exports
Shim export tells RequireJS what member on the global object (the window, assuming you're in a browser, of course) is the actual module value. Lets say moduleA adds itself to the window as 'modA'(just like jQuery and underscore does as $ and _ respectively), then we make our exports value 'modA'.
require.config({
shim:{
moduleA:{
exports:'modA'
}
}
It will give RequireJS a local reference to this module. The global modA will still exist on the page too.
-Custom initialization for older "browser global" scripts
This is probably the most important feature of shim config which allow us to add 'browser global', 'non-AMD' scripts(that do not follow modular pattern either) as dependencies in our own module.
Lets say moduleB is plain old javascript with just two functions funcA() and funcB().
function funcA(){
console.log("this is function A")
}
function funcB(){
console.log("this is function B")
}
Though both of these functions are available in window scope, RequireJS recommends us to use them through their global identifier/handle to avoid confusions. So configuring the shim as
shim: {
moduleB: {
deps: ["jquery"],
exports: "funcB",
init: function () {
return {
funcA: funcA,
funcB: funcB
};
}
}
}
The return value from init function is used as the module export value instead of the object found via the 'exports' string. This will allow us to use funcB in our own module as
require(["moduleA","moduleB"], function(A, B){
B.funcB()
})
Hope this helped.
You must add paths in requirejs.config to declare, example:
requirejs.config({
paths: {
'underscore' : '.../example/XX.js' // your JavaScript file
'jquery' : '.../example/jquery.js' // your JavaScript file
}
shim: {
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'underscore': {
exports: '_'
},
'foo': {
deps: ['bar'],
exports: 'Foo',
init: function (bar) {
return this.Foo.noConflict();
}
}
}
});
Related
i read the requirejs document from here api
requirejs.config({
baseUrl: 'js/',
paths: {
app: 'app/js',
jquery: '',
},
shim: {
jquery: {
exports: '$',
},
knockout: {
deps: ['jquery', 'bootstrap', 'underscore'],
exports: 'KnockOut'
},
underscore: {
exports: '_'
},
a:{
deps: ['x','b'],
exports: 'a'
}
}
});
but i am not getting deps part of shim.
why should i use deps and does that mean these files(x and b) will auto load if i load only a or what else
require(['a'], function(a){
});
I tried but couldn't getting auto load x and b.
please can any one explain with example why and when should we use deps.
thanks.
RequireJS loads modules that conform to the Asynchronous Module Definition (AMD). An AMD module must call a function named define provided by the AMD loader. The basic call is like this:
define(["a", "b", "c", ...], function (a, b, c, ...) {
});
The first argument is a list of the modules that the module being defined depends on. The 2nd argument is a factory function that builds the module being defined. RequireJS passes to it the modules that were listed in the dependencies. There are other ways to call define but the example above is typical.
That's all nice and well but what happens if you want to load a library produced by a third party but that is not an AMD module? The shim option allows telling RequireJS how to load those modules. For an AMD module, you specify dependencies in the array you pass to define, but for a non-AMD module you define a shim that contains a list of dependencies in the deps option. It contains the name of modules that must be loaded before the shimmed module is loaded. In your example, x and b must be loaded before a.
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'll use what I'm actually doing as an example. I have a knockout custom binding that depends on a jquery plugin that itself depends on jQuery UI that of course depends on jQuery. There is another file that depends on another plugin, and another file that depends on jQuery UI, etc. In require.config.js I have:
shim: {
"jquery-ui": {exports: "$", deps: ["jquery"]},
"jquery-plugin1": {exports: "$", deps: ["jquery-ui"]},
"jquery-plugin2": {exports: "$", deps: ["jquery-ui"]}
}
This works, and then in corresponding files I may do:
define(["jquery-plugin1"], function ($) {
However, I could also do:
define(["jquery", "jquery-ui", "jquery-plugin1"], function ($) {
There is also the case where a file may depend on both plugins:
// which one?
define(["jquery-plugin1", "jquery-plugin2"], function ($) {
define(["jquery", "jquery-ui", "jquery-plugin1", "jquery-plugin2"], function ($){
There may also be other dependencies such as knockout custom bindings (which don't need to export anything) so I may end up with:
define(["jquery-plugin1", "model1", "model2",
"ko-custom1", "ko-custom2", "ko-custom3",
"jquery-plugin2"],
function ($, m1, m2) {
This file may also depend on jQuery UI (which depends on jQuery), but those are both loaded implicitly via the plugins.
My question is is it better to be explicit about all requirements (i.e. include jQuery and jQuery-UI in define) and possibly leave off the exports, or is the less-verbose nested dependency handling preferred?
This is a great question and becomes very relevant when using something like AngularJS dependency injection as those dependencies need to exist before the module is registered. So this won't work:
define(['angular'],function (angular) {
return angular.module('myModule', ['mySubmodule']);
});
// Error: [$injector:nomod] Module 'mySubmodule' is not available!
You need to define the AMD dependency as well:
define(['angular','./mySubmodule'],function (angular) {
return angular.module('myModule', ['mySubmodule']);
});
It might be subjective but I find it easier to reason about it by having each module define it's own dependencies explicitly and letting requireJS resolve them instead of leaving it up to faith that an out-of-scope module has already defined them which breaks modularity.
By doing this you also know that your AMD modules can be tested independently without rewiring the missing dependency.
I'm attempting to load the Highcharts library using a shim in RequireJS. However, when Highcharts loads, it throws an exception because it can't access the jQuery methods it depends on.
The require config looks like so:
require.config({
baseUrl: "js",
shim: {
'libs/highcharts/highcharts.src.js': {
deps: ['jquery'],
exports: function(jQuery)
{
this.HighchartsAdapter = jQuery;
return this.Highcharts;
}
}
}
});
The exception that is thrown is:
Uncaught TypeError: undefined is not a function
and is in regards to this line:
dataLabels: merge(defaultLabelOptions, {
The issue is the merge call, which eventually maps itself back to jQuery (or some other adapter that Highcharts supports; but I'm just using jQuery).
I'm not sure exactly how to make sure Highcharts gets access to jQuery using RequireJS and shim.
Has anyone used RequireJS and Highcharts together before? I guess the issue isn't specific to highcharts, but any library that has other sorts of dependencies.
Thanks in advance for any advice or points to the correct direction!
To add further context, in hopes that someone who is familiar with require.js or shims will be able to help without having to be too intimately familiar with highcharts, here's some source that sets up this merge method in Highcharts
var globalAdapter = win.HighchartsAdapter,
adapter = globalAdapter || {},
// Utility functions. If the HighchartsAdapter is not defined,
// adapter is an empty object
// and all the utility functions will be null. In that case they are
// populated by the
// default adapters below.
// {snipped code}
merge = adapter.merge
// {snipped code}
if (!globalAdapter && win.jQuery) {
var jQ = win.jQuery;
// {snipped code}
merge = function () {
var args = arguments;
return jQ.extend(true, null, args[0], args[1], args[2], args[3]);
};
// {snipped code}
}
The win object is a reference set up to window at the beginning of the script. So, I thought adding window.jQuery = jQuery; to the export method on the shim would result in highcharts picking up the jQuery reference; but it didn't.
Again, any insight, info, advice, or heckles would be appreciated at this point - I'm at a complete loss, and starting to question whether trying to implement and AMD package system in browser javascript is even worth it.
After accepting the answer from pabera below I thought it appropriate to update my question to reflect how his answer helped my solution (though, it's basically his answer).
RequireJS uses "paths" to find libs that aren't "AMD" supported and loads them on your page. the "shim" object allows you to define dependencies for the libraries defined in paths. The dependencies must be loaded before requirejs will try to load the dependent script.
The exports property provides a mechanism to tell requirejs how to determine if the library is loaded. For core libs like jquery, backbone, socketio, etc they all export some window level variable (Backbone, io, jQuery and $, etc). You simply provide that variable name as the exports property, and requirejs will be able to determine when the lib is loaded.
Once your definitions are done, you can use requirejs' define function as expected.
Here's my example require.config object:
require.config({
baseUrl: "/js/",
paths: {
jquery: 'jquery',
socketio: 'http://localhost:8000/socket.io/socket.io', //for loading the socket.io client library
highcharts: 'libs/highcharts/highcharts.src',
underscore: 'libs/underscore',
backbone: 'libs/backbone'
},
shim: {
jquery: {
exports: 'jQuery'
},
socketio: {
exports: 'io'
},
underscore: {
exports: '_'
},
backbone: {
deps: ['jquery', 'underscore'],
exports: 'Backbone'
},
highcharts: {
deps: ['jquery'],
exports: 'Highcharts'
}
}
});
As pabera mentioned before, this is for Require.JS version 2.0.1.
I hope someone gets some use out of this; I know it road blocked me for a little while; so hopefully we kept you from banging your head into the same spot in the wall that we did, by posting this.
I had the exact same problem and I was struggling around many hours until I saw your entry here. Then I started over from scratch and now it works for me at least.
requirejs.config({
baseUrl:'/js/',
paths:{
jquery:'vendor/jquery',
handlebars: 'vendor/handlebars',
text: 'vendor/require-text',
chaplin:'vendor/chaplin',
underscore:'vendor/underscore',
backbone:'vendor/backbone',
highcharts: 'vendor/highcharts'
},
shim: {
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
underscore: {
exports: '_'
},
highcharts: {
exports: 'Highcharts'
}
},
});
Since I use Chaplin on top of Backbone, I am including some more files in my paths attribute. Highcharts has a similar structure to Backbone so I thought I could load it the same way. It works for me now. As you can see, I am introducing highcharts in the paths attribute already to export it as a shim afterwords.
Maybe this helps, otherwise let's try to contribute on it even more to solve your problem.
Although jQuery can be used as an AMD module it will still export itself to the window anyway so any scripts depending on the global jQuery or $ will still work as long as jQuery has loaded first.
Have you tried setting a path? jQuery is an interesting one because although you're encoruaged not to name your modules by the RequireJS documentation, jQuery actually does.
From the jQuery source
if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
define( "jquery", [], function () { return jQuery; } );
}
What that means is you will need to tell RequireJS where to find 'jquery'. So:
require.config({
paths: {
'jquery': 'path/to/jquery'
}
});
If you're interested in why jQuery registers itself this way then there is a pretty large comment in the source which goes into more detail
I'm trying to load Backbone and Underscore (as well as jQuery) with RequireJS. With the latest versions of Backbone and Underscore, it seems kind of tricky. For one, Underscore automatically registers itself as a module, but Backbone assumes Underscore is available globally. I should also note that Backbone doesn't seem to register itself as a module which makes it kind of inconsistent with the other libs. This is the best main.js I could come up with that works:
require(
{
paths: {
'backbone': 'libs/backbone/backbone-require',
'templates': '../templates'
}
},
[
// jQuery registers itself as a module.
'http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js',
// Underscore registers itself as a module.
'http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.2.1/underscore-min.js'
], function() {
// These nested require() calls are just due to how Backbone is built. Underscore basically says if require()
// is available then it will automatically register an "underscore" module, but it won't register underscore
// as a global "_". However, Backbone expects Underscore to be a global variable. To make this work, we require
// the Underscore module after it's been defined from within Underscore and set it as a global variable for
// Backbone's sake. Hopefully Backbone will soon be able to use the Underscore module directly instead of
// assuming it's global.
require(['underscore'], function(_) {
window._ = _;
});
require([
'order!http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.5.3/backbone-min.js',
'order!app'
], function(a, app) {
app.initialize();
})
});
I should mention that, while it works, the optimizer chokes on it. I receive the following:
Tracing dependencies for: main
js: "/home/httpd/aahardy/requirejs/r.js", line 7619: exception from uncaught JavaScript throw: Error: Error: Error evaluating module "undefined" at location "/home/httpd/aahardy/phoenix/trunk/ui/js/../../ui-build/js/underscore.js":
JavaException: java.io.FileNotFoundException: /home/httpd/aahardy/phoenix/trunk/ui/js/../../ui-build/js/underscore.js (No such file or directory)
fileName:/home/httpd/aahardy/phoenix/trunk/ui/js/../../ui-build/js/underscore.js
lineNumber: undefined
http://requirejs.org/docs/errors.html#defineerror
In module tree:
main
Is there a better way of handling this? Thanks!
RequireJS 2.X now organically addresses non-AMD modules such as Backbone & Underscore much better, using the new shim configuration.
The shim configuration is simple to use: (1) one states the dependencies (deps), if any, (which may be from the paths configuration, or may be valid paths themselves). (2) (optionally) specify the global variable name from the file you're shimming, which should be exported to your module functions that require it. (If you don't specify the exports, then you'll need to just use the global, as nothing will get passed into your require/define functions.)
Here is a simple example usage of shim to load Backbone. It also adds an export for underscore, even though it doesn't have any dependencies.
require.config({
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
}
}
});
//the "main" function to bootstrap your code
require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone) { // or, you could use these deps in a separate module using define
});
Note: this simplified code assumes that jquery, backbone and underscore are in files named "jquery.js", "backbone.js" and "underscore.js" in the same directory as this "main" code (which becomes the baseURL for require). If this isn't the case, you'll need to use a paths config.
I personally think with the built-in shim functionality, the advantages of not using a forked version of Backbone & Underscore outweigh the benefits of using the AMD fork recommended in the other popular answer, but either way works.
Update: As of version 1.3.0 Underscore removed AMD (RequireJS) support.
You can use the amdjs/Backbone 0.9.1 and the amdjs/Underscore 1.3.1 fork with AMD support from James Burke (the maintainer of RequireJS).
More info about AMD support for Underscore and Backbone.
// main.js using RequireJS 1.0.7
require.config({
paths: {
'jquery': 'libs/jquery/1.7.1/jquery',
'underscore': 'libs/underscore/1.3.1-amdjs/underscore', // AMD support
'backbone': 'libs/backbone/0.9.1-amdjs/backbone', // AMD support
'templates': '../templates'
}
});
require([
'domReady', // optional, using RequireJS domReady plugin
'app'
], function(domReady, app){
domReady(function () {
app.initialize();
});
});
The modules are properly registered and there is no need for the order plugin:
// app.js
define([
'jquery',
'underscore',
'backbone'
], function($, _, Backbone){
return {
initialize: function(){
// you can use $, _ or Backbone here
}
};
});
Underscore is actually optional, because Backbone now gets its dependencies on its own:
// app.js
define(['jquery', 'backbone'], function($, Backbone){
return {
initialize: function(){
// you can use $ and Backbone here with
// dependencies loaded i.e. Underscore
}
};
});
With some AMD sugar you could also write it like this:
define(function(require) {
var Backbone = require('backbone'),
$ = require('jquery');
return {
initialize: function(){
// you can use $ and Backbone here with
// dependencies loaded i.e. Underscore
}
};
});
Regarding the optimizer error: doublecheck your build configuration. I assume your path configuration is off. If you have a directory setup similar to the RequireJS Docs you can use:
// app.build.js
({
appDir: "../",
baseUrl: "js",
dir: "../../ui-build",
paths: {
'jquery': 'libs/jquery/1.7.1/jquery',
'underscore': 'libs/underscore/1.3.1-amdjs/underscore',
'backbone': 'libs/backbone/0.9.1-amdjs/backbone',
'templates': '../templates'
},
modules: [
{
name: "main"
}
]
})
For reference, as of version 1.1.1 (~Feb '13), Backbone also registers itself as an AMD module. It will work with requirejs without the need to use its shim config. (James Burke's amdjs fork also hasn't been updated since 1.1.0)
Good news, Underscore 1.6.0 now supports requirejs define !!!
versions below this require shims, or requiring underscore.js then blindly hoping that the "_" global variable hasn;t been smashed (which to be fair is a fair bet)
simply load it in by
requirejs.config({
paths: {
"underscore": "PATH/underscore-1.6.0.min",
}
});
I will write down directly, you can read the explaination on requirejs.org, you could use below code as a snippet for your everyday use; (p.s. i use yeoman) (since many things updated, im posting this as of Feb 2014.)
Make sure you included script in your index.html
<!-- build:js({app,.tmp}) scripts/main.js -->
<script data-main="scripts/main" src="bower_components/requirejs/require.js"></script>
<!-- endbuild -->
Then, in main.js
require.config({
shim: {
'backbone': {
deps: ['../bower_components/underscore/underscore.js', 'jquery'],
exports: 'Backbone'
}
},
paths: {
jquery: '../bower_components/jquery/jquery',
backbone: '../bower_components/backbone/backbone'
}
});
require(['views/app'], function(AppView){
new AppView();
});
app.js
/**
* App View
*/
define(['backbone', 'router'], function(Backbone, MainRouter) {
var AppView = Backbone.View.extend({
el: 'body',
initialize: function() {
App.Router = new MainRouter();
Backbone.history.start();
}
});
return AppView;
});
I hope I was useful.!
require.config({
waitSeconds: 500,
paths: {
jquery: "libs/jquery/jquery",
jqueryCookie: "libs/jquery/jquery.cookie",
.....
},
shim: {
jqxcore: {
export: "$",
deps: ["jquery"]
},
jqxbuttons: {
export: "$",
deps: ["jquery", "jqxcore"]
}
............
}
});
require([
<i> // Load our app module and pass it to our definition function</i>
"app"
], function(App) {
// The "app" dependency is passed in as "App"
// Again, the other dependencies passed in are not "AMD" therefore don't pass a parameter to this function
App.initialize();
});