In my project I would like to use backbone.babysitter, but I can't make it work.
I use require.js to load the modules, now my config looks like this.
requirejs.config({
paths: {
'underscore': 'lib/underscore',
'backbone': 'lib/backbone',
'backbone.babysitter': 'lib/backbone.babysitter',
'jquery': 'lib/jquery',
},
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ['underscore','jquery'],
exports: 'Backbone'
}
}
});
I use the AMD version of backbone.babysitter
When I do later in my code
require( ['backbone.babysitter'], function(){
var v = Backbone.ChildViewContainer();
});
I got the following error:
Uncaught TypeError: Object #<Object> has no method '_updateLength' backbone.babysitter.js:41
What am I doing wrong?
If backbone.babysitter depends on backbone and underscore you should state that between your dependencies:
'backbone.babysitter': {
deps: ['backbone', 'underscore']
}
since backbone already depends on unserscore and jquery:
'backbone.babysitter': {
deps: ['backbone']
}
would be sufficient.
I think you are not passing it to the function as parameter, but also you need to pass backbone:
require( ['backbone'], function(Backbone){
var v = Backbone.ChildViewContainer();
});
That should fix it.
I could make it work with not the AMD version of the lib like this.
under shim:
'backbone.babysitter': {
deps: ['backbone','underscore']
},
and require like this:
require( ['backbone.babysitter'], function(){
var v = new Backbone.ChildViewContainer();
});
Related
I'd like to know how to load Underscore and Backbone using RequireJS and be able to configure Underscore before it's passed to Backbone.
I've seen this popular question on StackOverflow about this similar topic, but I haven't been able to figure out how to get Underscore to be configured for both of the following situations:
Underscore is required by itself
Underscore is loaded by Backbone
So my question is the following:
How can I configure Underscore using RequireJS when required by itself, and when required with Backbone in a module?
Here's what I've tried:
Approach that should work, but DOESN'T:
My first idea (as suggested here) was to define a requireJS module named (e.g.) rawUnderscore which returns Underscore without any configuration. Then, create a new module named underscore which requires rawUnderscore and configures it before returning its value. This causes loading problems (couldn't load backbone)
Configure Require.js modules
// When you initially setup require.js, add a new module to configure underscore
// Make it a dependency of backbone, so it'll always be loaded whenever
// backbone is used.
require.config({
paths: {
'underscore': 'underscoreConfig',
'rawUnderscore': 'underscoreOriginal'
},
shim: {
underscore: {
deps: ['rawUnderscore', 'jquery'],
exports: '_'
},
backbone: {
deps: ['underscore'],
exports: 'Backbone'
},
jquery: {
exports: 'jQuery'
}
}
});
underscoreConfig.js
define(['rawUnderscore'], function (_) {
'use strict';
_.templateSettings =
{
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%cleanHtml([\s\S]+?)%>/g,
escape : /<%[=-]([\s\S]+?)%>/g
};
return _;
});
Approach that works - Edit Underscore and remove AMD ability:
This works if I remove the AMD lines from Underscore.js (ie force Underscore to not be AMD compliant). I'd prefer not to do this as I like to keep libraries as they are, to ease future maintenance.
Configure Require.js to use the underscore patch
require.config({
shim: {
underscore: {
deps: ['underscorePatch'],
exports: '_',
init: function(patchIt){
return patchIt(this._);
}
}
}
});
underscorePatch.js
define('underscorePatch', [], function(){
'use strict';
function patch(_){
_.templateSettings = {
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%cleanHtml([\s\S]+?)%>/g,
escape : /<%[=-]([\s\S]+?)%>/g
};
return _;
}
return patch;
});
Approach that works when loaded with Backbone:
This approach works, but only in the context of when Backbone being loaded as well. Not when Underscore is required by itself.
Configure Require.js modules
// When you initially setup require.js, add a new module to configure underscore
// Make it a dependency of backbone, so it'll always be loaded whenever
// backbone is used.
require.config({
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ['underscoreConfig', 'underscore', 'jquery'],
exports: 'Backbone'
},
jquery: {
exports: 'jQuery'
}
}
});
underscoreConfig.js
define(['underscore'], function (_) {
'use strict';
_.templateSettings =
{
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%cleanHtml([\s\S]+?)%>/g,
escape : /<%[=-]([\s\S]+?)%>/g
};
return _;
});
I think your first example was on the right track. The following seems to work:
main.js
requirejs.config({
paths: {
'underscore': 'underscoreConfig',
'originalUnderscore': 'underscore'
},
shim: {
'originalUnderscore': {
exports: '_'
}
}
});
underscoreConfig.js
define(['originalUnderscore'], function(_) {
_.templateSettings =
{
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%cleanHtml([\s\S]+?)%>/g,
escape : /<%[=-]([\s\S]+?)%>/g
};
return _;
});
My main.js look as below
requirejs.config({
//By default load any module IDs from ../js
baseUrl: '../js',
paths : {
'jquery': 'libs/jquery',
'underscore': 'libs/underscore',
'backbone': 'libs/backbone',
'bootstrap': 'libs/bootstrap'
},
shim: {
'jquery': {
exports: '$'
},
'backbone': {
//These script dependencies should be loaded before loading
//backbone.js
deps: ['jquery', 'underscore'],
//Once loaded, use the global 'Backbone' as the
//module value.
exports: 'Backbone'
},
'underscore': {
exports: '_'
},
'bootstrap': {
deps: ['jquery'],
exports: 'Bootstrap'
}
}
});
define(
['jquery', 'backbone','underscore', 'bootstrap'],
function (j, b, u, boot) {
console.log('jquery', j);
console.log('backbone', b);
console.log('underscore',u);
console.log('bootstrap', boot);
}
);
And my console image is like this:
When I click on X sign in alert, they disappear. So, I think bootstrap.js is loaded correctly. However, it says undefined in console. Can anyone make me clear is the bootstrap.js is loaded correctly and safe to use? And why it is saying undefined while rest of are defined well in console.
As jquery, backbone, and underscore export global variables to be used elsewhere, while bootstrap will just take the existing jquery object and will add plugins to the object, hence it won't export anything.
So, if you try to receive it in define callback, ideally it will be undefined. If you've used any bootstrap component on the page and if it is working it means bootstrap is integrated.
From the requirejs shim docs
For "modules" that are just jQuery or Backbone plugins that do not need to export any module value, the shim config can just be an array of dependencies:
requirejs.config({
shim: {
'bootstrap': ['jquery']
}
});
So, if you want, you can declare bootstrap like its specified in the docs.
I'm trying to setup a vent/EventAggregator as a separate Require.js module. I am using Marionette 1.0.2 (which I believe has a different implementation than legacy versions pre 1.0.0) with wreqr included: this code is from backbone.marionette.js:-
// Event Aggregator
// ----------------
// A pub-sub object that can be used to decouple various parts
// of an application through event-driven architecture.
Wreqr.EventAggregator = (function(Backbone, _){
"use strict";
var EA = function(){};
// Copy the `extend` function used by Backbone's classes
EA.extend = Backbone.Model.extend;
// Copy the basic Backbone.Events on to the event aggregator
_.extend(EA.prototype, Backbone.Events);
return EA;
})(Backbone, _);
When I set up my vent.js module what should it be? Something like this:-
define(['marionette'],function(Marionette){
return new Marionette.EventAggregator();
})
Also in my require config should I explicitly be including backbone.wreqr.js or not? Or should just the marionette file (see snippet from above) be sufficient?
For reference here is my app.js:-
require.config({
paths : {
backbone : 'lib/backbone',
underscore : 'lib/underscore',
jquery : 'lib/jquery',
marionette : 'lib/backbone.marionette',
'backbone.wreqr' : 'lib/backbone.wreqr',
text : 'lib/text',
templates : '../templates'
},
shim : {
jquery : {
exports : 'jQuery'
},
underscore : {
exports : '_'
},
backbone : {
deps : ['jquery', 'underscore'],
exports : 'Backbone'
},
marionette : {
deps : ['jquery', 'underscore', 'backbone'],
exports : 'Marionette'
},
'backbone.wreqr' : {
deps : ['backbone', 'marionette', 'underscore'],
exports : 'Wreqr'
}
}
})
require(
["jquery",
"underscore",
"backbone",
"marionette",
"backbone.wreqr",
"shell/shellapp"
],
function($, _, Backbone, Marionette, Wreqr, ShellApp) {
$(function() {
//new ShellApp();
var shell = ShellApp;
shell.start();
trace("shell: "+shell);
});
}
);
All help much appreciated!
Much thanks,
Sam
_______**** UPDATE
Thanks to Paul I figured out how to get my vent.js working. FYI I did NOT need to import the wreqr file seperately in the config. Here is the vent.js code:-
define(['backbone', 'marionette'],function(Backbone, Marionette){
return new Backbone.Wreqr.EventAggregator();
});
This works for me.
require.config({
paths: {
backbone: 'http://backbonejs.org/backbone',
underscore: 'http://underscorejs.org/underscore',
jquery: 'http://code.jquery.com/jquery-1.9.1',
marionette: 'http://marionettejs.com/downloads/backbone.marionette'
},
shim: {
jquery: {
exports: 'jQuery'
},
underscore: {
exports: '_'
},
backbone: {
deps: ['jquery', 'underscore'],
exports: 'Backbone'
},
marionette: {
deps: ['jquery', 'underscore', 'backbone'],
exports: 'Marionette'
}
}
});
require(["backbone", "marionette"], function (Backbone, Marionette) {
console.log(Backbone.Wreqr.EventAggregator);
var ea = new Backbone.Wreqr.EventAggregator();
console.log(ea);
});
I have a Backbone app that gets errors of Backbone is not defined non-deterministically from different spots in my code that use Backbone. Sometimes it loads first and the site loads, other times it doesn't. I'm using the following as my main.js:
require.config({
paths: {
jqueryui: 'libs/jquery/jquery-ui',
underscore: 'libs/underscore/underscore-min',
backbone: 'libs/backbone/backbone-min',
text: 'libs/require/text',
order: 'libs/require/order',
searchcollector: 'libs/jquery/searchcollector.plugin',
guiders: 'libs/jquery/guiders'
},
shim: {
'underscore': {
exports: '_'
},
'backbone': {
deps: ['underscore'],
exports: 'Backbone'
}
}
});
require([
'views/app',
'helpers'
], function(app) {
var app = window.app = new app();
});
I'm using
<script data-main="/assets/js/main" src="/assets/js/libs/require/require-jquery.js"></script>
in my HTML so jQuery is loaded with the require. I took this advice from this (http://stackoverflow.com/questions/8131265/loading-backbone-and-underscore-using-requirejs) SO thread, but nothing seems to be working. Shouldn't the Shim be loading the Backbone first and then making it globally available? Any help appreciated.
Not sure if this is the correct answer but I've noticed that you don't list jquery as a Backbone dependency. While Backbone lists Underscore as the only hard dependency, Backbone.View will need jquery or zepto to work.
But why then, does it seem to work some of the time?
It might be that since jQuery is an AMD module, when you load, it sometimes loads first, and other times it doesn't. When it loads before Backbone, it is available and Backbone is happy. Otherwise, perhaps, the bad results you are getting.
Try something like this:
In your path add this:
jquery: 'libs/require/require-jquery'
And in your shim, add this:
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
}
Let me know what you get as a result. I've never used the shim feature of requirejs2.0 so I'm curious whether I'm understanding the deeper stuff correctly.
In my opinion it's a little bit hacky to load require and jquery in the same file.
And set jquery as a deps for Backbone is false because Underscore need jquery, and it's loaded before Backbone so the correct way is like this
require.config({
paths: {
'jquery': 'path to jquery'
,'underscore': 'path to underscore'
,'backbone': 'path to backbone'
**other paths...**
}
,shim: {
jquery: {
exports: '$'
}
,'underscore': {
deps: [ 'jquery' ]
,exports: '_'
}
,'backbone': {
deps: [ 'underscore' ]
,exports: 'Backbone'
}
}
});
Finally your tag script will be
<script data-main="/assets/js/main" src="/assets/js/libs/require.js">
</script>
Then you just have to call lib you need like this
define( [ 'jquery', 'underscore', 'backbone' ],
function( $, _, Backbone )
{
// stuff
} );
And for a model you maybe don't need jquery and underscore so just calling Backbone will work
define( [ 'backbone' ],
function( Backbone )
{
// Backbone.extend ?
} );
I have defined a RequireJs configuration which defines paths and shims:
require.config({
// define application bootstrap
deps: ["main"],
// define library shortcuts
paths: {
app: "app"
, jquery: "lib/jquery"
, underscore: "lib/underscore"
, backbone: "lib/backbone"
, bootstrap: "lib/bootstrap"
},
// define library dependencies
shim: {
jquery: {
exports: "$"
},
underscore: {
exports: "_"
},
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
},
bootstrap: {
deps: ['jquery'],
exports: "bootstrap"
},
// main application
app: {
deps: ["backbone"],
exports: "App"
}
}
});
As you see the last "shim" declaration should make it able to access backbone (and it deps) when I load the main App(-namespace).
In reality this doesn't work:
require(["app"], function($, _, Backbone, App){
app.router = new Backbone.Router.extend({
// routing and route actions
});
});
What makes me wondering is that in the "backbone-boilderplate"-project, Backbone (and its deps) are available this way:
https://github.com/tbranyen/backbone-boilerplate/blob/master/app/main.js
The not even had to define this in the function.
So what am I doing wrong?
From what I've read, requirejs passes arguments based on what you specify in the array... Thus your call should look like this:
require(["app"], function (App) { // less arguments
});
Or like this:
require(
["jquery", "underscore", "backbone", "app"], // more deps
function ($, _, Backbone, App) {
}
);
Remove the $, _, Backbone-parameters from the require-function where you extend the Router. The shims export global values, so there is no need to reference to them in require or define calls like you do for regular dependencies.
Passing them as parameters messes with the global variables and most likely results in them being undefined.