Loading Backbone and Underscore using RequireJS - javascript

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

Related

"Error: Module name 'underscore' has not been loaded yet for context: _" happens sometimes on Firefox only

This code is working fine on Chrome, IE and also android and IOS but an issue occurs sometimes on Firefox. After a few reload of the page the issue is gone!
Error: Module name 'underscore' has not been loaded yet for context: _
http://requirejs.org/docs/errors.html#notloaded require.js (line 7, col 217)
The code :
core.js
require.config({
paths: {
text: 'libs/text',
loader: 'libs/backbone/loader',
jQuery: 'libs/jquery/jquery',
Underscore: 'libs/underscore/underscore',
Backbone: 'libs/backbone/backbone',
'hammer': 'libs/jquery/hammer-min'
},
shim: {
Underscore: { deps: ['jQuery'] },
Backbone: { deps: ['Underscore'] }
}
});
require(['routers/core'], function (App) {
jQuery(document).ready(function () {
App.start();
});
});
routers/core.js
define([
'jQuery',
'Underscore',
'Backbone',
'routers/common'
], function ($, _, Backbone, CommonRouter) {
var start = function () {
var app = {
init: function () {
}
};
_.extend(CommonRouter.prototype, app);
var app_router = new CommonRouter;
Backbone.history.start();
};
return { start: start };
});
libs/backbone/loader.js
define([
'libs/jquery/jquery-base64',
'libs/jquery/jquery-easing',
'libs/jquery/jquery-inputmask',
'libs/jquery/jquery-mousewheel',
'libs/jquery/jquery-tagsinput',
'libs/jquery/jquery-validate',
'libs/jquery/highcharts',
'libs/jquery/raphael',
'libs/jquery/selectreplace',
'libs/jquery/touchswipe',
'libs/jquery/flowplayer-min',
'libs/underscore/underscore-min',
'libs/backbone/backbone-min'
],
function(){
return {
Backbone: Backbone.noConflict(),
_: _.noConflict(),
$: jQuery.noConflict()
};
});
The issue is that Backbone: Backbone.noConflict(), is undefined because the module "underscore" is not loaded yet.
How can I wait and be sure the modules required are loaded when I need them?
To answer your question:
How can I wait and be sure the modules required are loaded when I need them?
We can use the shim option of configuration for that.
To setup jQuery and underscore as dependencies of backbone you should do:
shim: {
backbone: { deps: ['jQuery','underscore'] }
}
You seem to have setup jQuery as a dependency of underscore where there is no actual dependency between them, which is unnecessary.
Apart from that you seems to have few issues -
First of all, you haven't specified any arguments to your libs/backbone/loader.js module. Since there is no global backbone or _ in window, unless you specify these your module won't have a way to access to the exports apart from the arguments object, unless somehow it's available in it's the parent scope.
Most of your imports seems to be jQuery plugins that just modifies jQuery. In such case you should specify them after all other libs that actually exports something which you want to use so that you don't have to specify an argument for each.
another issue could be that you're using the short path names to setup the shim option but you're using the full path (for eg libs/backbone/backbone-min) to load the libraries in libs/backbone/loader.js.
I wonder how it works for you in other browsers without specifying the import names as arguments.
define([
'underscore',
'jquery',
'backbone'
'libs/jquery/jquery-base64',
'libs/jquery/jquery-easing',
'libs/jquery/jquery-inputmask',
'libs/jquery/jquery-mousewheel',
'libs/jquery/jquery-tagsinput',
'libs/jquery/jquery-validate',
'libs/jquery/highcharts',
'libs/jquery/raphael',
'libs/jquery/selectreplace',
'libs/jquery/touchswipe',
'libs/jquery/flowplayer-min'
],
function(_,
$,
Backbone
/*all other imports in order*/
) {
return {
Backbone: Backbone.noConflict(),
_: _.noConflict(),
$: jQuery.noConflict()
};
});
side note: I modified the first letter of path names to small letter because I prefer having a consistent naming convention

What does requirejs.config() do?

I am having trouble understanding about requirejs.config() function.
requirejs.config({
paths: {
'text': '../lib/require/text',
'durandal':'../lib/durandal/js',
'plugins' : '../lib/durandal/js/plugins',
'transitions' : '../lib/durandal/js/transitions',
'knockout': '../lib/knockout/knockout-3.1.0',
'bootstrap': '../lib/bootstrap/js/bootstrap',
'jquery': '../lib/jquery/jquery-1.9.1'
},
shim: {
'bootstrap': {
deps: ['jquery'],
exports: 'jQuery'
}
}
});
What does the function do? Please do not direct me to the documentation because I have read it and still found it confusing. I need a simple explanation on what this function does.
Are these scripts loaded asynchronously?
It creates aliases for script paths ant tells how to interpret bootstrap (non-AMD script) when loaded. Nothing is loaded yet. You have to require:
// we load two dependencies here
// `knockout` and `bootstrap` are expanded to values in config
// .js added to values
// callback function called when all dependencies are loaded
require(['knockout', 'bootstap'], function(Knockout, $) {
// jQuery is passed to this function as a second parameter
// as defined in shim config exports
});
The path is like declarations/definitions. So for example,
jquery: '../bower_components/jquery/dist/jquery',
you can later load this lib as follows.
define([
'jquery'
], function (jquery) {
//initialize or do something with jquery
}
You don't have to specify the absolute path of the library.
In shim, you will define dependencies. So for example,
paths: {
template: '../templates',
text: '../bower_components/requirejs-text/text',
jquery: '../bower_components/jquery/dist/jquery',
backbone: '../bower_components/backbone/backbone',
underscore: '../bower_components/underscore/underscore',
Router: 'routes/router'
},
shim: {
'backbone': ['underscore', 'jquery'],
'App': ['backbone']
}
Here backbone is dependent on underscore and jquery. So those two libs will be loaded before backbone starts loading. Similarly App will be loaded after backbone is loaded.
You might find this repo useful if you are familiar with backbone and express.
https://github.com/sohel-rana/backbone-express-boilerplate

Requirejs why and when to use shim config

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

Cannot get requirejs to include Backbonejs

I am trying to modularize my Backbone app through Requirejs, but I cannot seem to get Requirejs to include Backbone. Here is my main.js that gets included from the index page:
require.config({
baseUrl: '/static/js/',
paths: {
jquery: 'libs/jquery/jquery-min',
underscore: 'libs/underscore/underscore-min',
backbone: 'libs/backbone/backbone-min',
text: 'libs/require/text',
},
});
require(['/static/js/views/app.js'], function(AppView) {
var appView = new AppView;
});
Here is my app.js that gets included from the above file:
define([
'jquery',
'underscore',
'backbone',
], function($, _, Backbone) {
console.log($);
console.log(_);
console.log("inside of the app js file");
var AppView = Backbone.View.extend({
initialize: function() {
console.log("inside of appview initialize");
},
});
});
The following information gets printed out in my Google Chrome console:
function (a,b){return new e.fn.init(a,b,h)}
app.js:7undefined
app.js:8inside of the app js file
app.js:9Uncaught TypeError: Cannot read property 'View' of undefined
The definition for $ works, but the definitions for _ and Backbone do not work. They come up as undefined. Any idea why this is happening?
I recommend you use the version of requireJS that has jQuery bundled. It will save you much setup pain. You can read the details here: http://requirejs.org/docs/jquery.html and download the files here: https://github.com/jrburke/require-jquery
In their own words:
With RequireJS, scripts can load in a different order than the order they are specified. This can cause problems for jQuery plugins that assume jQuery is already loaded. Using the combined RequireJS + jQUery file makes sure jQuery is in the page before any jQuery plugins load.
This should take care of loading jQuery properly with requireJS:
<script data-main="js/main" src="js/require-jquery.js"></script>
Main.js
A couple of notes here:
No need to re-define the path to jquery since that's already taken care of
You still have to indicate jquery as a required module
(I had to update the paths to have them work in my system)
Code:
require.config({
baseUrl: 'js/',
paths: {
underscore: 'libs/underscore-min',
backbone: 'libs/backbone-min',
},
});
require(['jquery', 'app'], function($, AppView) {
console.log("done w/ requires");
console.log($)
console.log(AppView)
var appView = new AppView;
});
app.js
A couple notes:
You can only retrieve the JS files after loading them in the callback if they have been defined as modules. So function($, _, Backbone) will fail for you.
You must return your object so that it can be used in the main.js callback (return AppView)
Code:
define(
[
'jquery',
'underscore',
'backbone',
],
function() {
console.log($);
console.log(_);
console.log(Backbone);
console.log("inside of the app js file");
return AppView = Backbone.View.extend({
initialize: function() {
console.log("inside of appview initialize");
},
});
});
Console
With that code in place, this is the console output:
function ( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
} [app.js:8]
function (a){return new m(a)} [app.js:9]
Object [app.js:10]
inside of the app js file [app.js:11]
done w/ requires main.js:21
function ( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
} [main.js:22]
function (){a.apply(this,arguments)} [main.js:23]
inside of appview initialize [app.js:15]
I would shy away from using forked versions of backbone and underscore. A "shim" configuration option has been added to requirejs to handle 3rd party libraries that don't natively support AMD. This makes updating to the latest versions of the libraries much easier.
http://requirejs.org/docs/api.html#config-shim
Here is an example:
require.config({
paths: {
jquery: "libs/jquery",
underscore: "libs/underscore",
backbone: "libs/backbone"
},
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
}
}
});
You may not have the correct reference backbone and _,may be this can help you:
Loading Backbone and Underscore using RequireJS
more:
http://requirejs.org/docs/api.html#config-shim

Loading mustache using requirejs

I would like to load and use mustache by requirejs.
Maybe this question has already asked:
AMD Module Loading Error with Mustache using RequireJS
Anyway I am trying to figure out how can I fix my code:
main.js
require.config({
paths: {
jquery: 'libs/jquery/jquery',
underscore: 'libs/underscore/underscore-min',
backbone: 'libs/backbone/backbone-optamd3-min',
mustache: "libs/mustache/mustache"
}
});
require([
'views/app'
], function(AppView){
var app_view = new AppView;
});
app.js
define([
'jquery',
'underscore',
'backbone',
"mustache"
], function($, _, Backbone, Mustache) {
console.log($, _, Backbone, Mustache); // <-- *** Mustache is null ***
// ......
}
);
As you can see in the comment on app.js file, Mustache is null...
Should I use another library of Mustache?
Here what I am using Mustache
Looks like Mustache supports AMD modules as of July '12. So it should now work out of the box with a loader such as require.js.
You should just create in your mustache directory a new file mustache-wrap.js which looks like this:
define(['libs/mustache/mustache'], function(Mustache){
// Tell Require.js that this module returns a reference to Mustache
return Mustache;
});
and then your main will be:
mustache: "libs/mustache/mustache-wrap"
Not sure if RequireJS 2.1.0 was out at the time of posting this question (and the answers) but the preferred way of handling this now is using shim config element (more info on project's docs page).
Your main.js would become:
require.config({
paths: {
jquery: 'libs/jquery/jquery',
underscore: 'libs/underscore/underscore-min',
backbone: 'libs/backbone/backbone-optamd3-min',
mustache: "libs/mustache/mustache"
},
shim: {
'mustache': {
exports: 'Mustache'
}
}
});
(...)
That's effectively the same as wrapper suggested #AntoJs, but without the boilerplate code.
...but then, since Mustache supports AMD there's no need to wrap/shim in the first place!
You could probably also do in-line named define in the code that consumes mustache, or somewhere in "main.js" (saves the trouble of creating *-wrap file)
define('mustache', ['libs/mustache/mustache'], function(){
// Tell Require.js that this module returns a reference to Mustache
return Mustache; // from global
});
require(
['jquery','underscore','backbone','mustache']
, function($, _, BB, Mustache){
// use them
}
)

Categories

Resources