Why is RequireJS ignoring my "paths" configuration? - backbone.js

As-salamu-alikum
I have config as follows
requirejs.config({
baseUrl: "assets/js/",
paths: {
"jq" : "lib/jquery/jquery",
"jqui" : "lib/jquery/jquery-ui-1.10.4",
"jl" : "lib/jquery/jquery.jlayout",
"jlb" : "lib/jquery/jlayout.border",
"jqs" : "lib/jquery/jquery.sizes",
"bb" : "lib/marionette/backbone",
"js2" : "lib/json2/json2",
"bbr" : "lib/marionette/backbone.radio",
"mt" : "lib/marionette/backbone.marionette",
"tk" : "lib/marionette/marionette.toolkit",
"us" : "lib/underscore/underscore",
"tpl" : "lib/tpl/tpl"
},
waitSeconds: 20,
shim: {
"jqui":{
deps: ['jq']
},
"jl":{
deps: ['jq']
},
"jqs":{
deps: ['jq']
},
"jlb":{
deps: ['jq']
},
"us": {
exports: "_"
},
"bb": {
exports: ["Backbone"],
deps: ['jq','us','js2']
},
"bbr":{
exports: ["Radio"],
deps: ["bb"]
},
"mt": {
exports: "Marionette",
deps: ["bb","bbr"]
},
"tk": {
exports: "Toolkit",
deps: ["mt"]
}
},
deps: ['app/main']
});
app/main is as follows
define([
"require",
"jq",
"jqui",
"jqs",
"jlb",
"jl",
"app/blogapp/bap"
],
function(
require,
$,
jLayout,
bap
){
'use strict';
jQuery(function($) {
var container = $('.layout');
function layout() {
container.layout({
resize: false,
type: 'border',
vgap: 8,
hgap: 8
});
};
$('.east').resizable({
handles: 'w',
stop: layout,
resize: layout
});
$('.west').resizable({
handles: 'e',
stop: layout,
resize: layout
});
$(window).resize(layout);
layout();
layout();
});
var BlogApp = require("app/blogapp/bap");
var blog = BlogApp.createApp();
blog.start(options);
},
function(
err
){
//The errback, error callback
//The error has a list of modules that failed
var failedId = err.requireModules && err.requireModules[0];
console.log("In err "+failedId);
console.log(err);
}
);
app/blogapp/bap is as follows
define(function (
require
){
var tk=require("tk");
var bb=require("bb");
var ba = tk.App.extend({
initialize: function() {},
});
return ba;
},
function(
err
){
//The errback, error callback
//The error has a list of modules that failed
var failedId = err.requireModules && err.requireModules[0];
console.log("In err "+failedId);
console.log(err);
}
);
I am getting the following error
GET file:///C:/Users/Nadvi/Desktop/blog.org/assets/js/backbone.js net::ERR_FILE_NOT_FOUND
req.load # require.js:2102
load # require.js:1784
load # require.js:900
fetch # require.js:890
check # require.js:922
enable # require.js:1246
enable # require.js:1644
(anonymous) # require.js:1231
(anonymous) # require.js:136
each # require.js:61
enable # require.js:1183
init # require.js:851
callGetModule # require.js:1273
completeLoad # require.js:1677
onScriptLoad # require.js:1823
require.js:388 function hasPathFallback(backbone)
require.js:170 Uncaught Error: Script error for "backbone", needed by: bbr
http://requirejs.org/docs/errors.html#scripterror
at makeError (require.js:170)
at HTMLScriptElement.onScriptError (require.js:1844)
Uncaught Error: Load timeout for modules: tk,mt
http://requirejs.org/docs/errors.html#timeout
at makeError (require.js:170)
at checkLoaded (require.js:743)
at require.js:769
makeError # require.js:170
checkLoaded # require.js:743
(anonymous) # require.js:769
setTimeout (async)
checkLoaded # require.js:767
(anonymous) # require.js:769
setTimeout (async)
checkLoaded # require.js:767
(anonymous) # require.js:769
setTimeout (async)
checkLoaded # require.js:767
(anonymous) # require.js:769
setTimeout (async)
checkLoaded # require.js:767
(anonymous) # require.js:769
What is going wrong here I can not understand how backbone.js path is going wrong.Please help me.
Zazakallah khair
Nadvi

You need to look at the libraries you are using and check whether they register themselves as AMD modules. The code for this typically looks like this:
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, _, $);
});
The one I have here is taken from Backbone. You see there that Backbone depends on the modules underscore, jquery, and exports. The exports module is one of the 3 internal modules provided internally by RequireJS. The other two internal modules are require and module. You don't need to do anything special for these internal modules: they are always available. However, RequireJS needs to be able to find modules named underscore and jquery. This is where you run into trouble. The error you get is because backbone.radio, which also calls define, depends on backbone. However, there is no module named backbone available anywhere in your configuration. What you do have is bb but "bb" !== "backbone" so RequireJS does not see it in the configuration and assumes it can be loaded from baseUrl and that fails.
There's an additional problem that some modules, jQuery being the most prominent example, call define with a hardcoded module name, like this:
define( "jquery", [], function() {
The first argument is the module name. Most of the time define is called with the list of dependencies as the first argument, and the module name is inferred. However, passing a string as the first argument hardcodes the module name. If you run into define calls like this, you must refer to the module by that hardcoded name. You cannot just put jq in your paths and point it to the jQuery file. When RequireJS loads jq it will find a module named jquery and will complain that they don't match.
My recommendations are:
Inspect everything you are loading and check the define calls as I explained above.
In your paths configuration put the usual names under which these libraries are named: jquery, backbone, underscore rather than the abbreviations.
Remove all shim configurations for modules that call define. shim is only for code that does not call define. Using shim for a module that calls define leads to undefined behavior. (At best it will be ignored.)
You can set a map configuration that will allow you to use abbreviations in your own code if you want. The map perform a module name substitution. For instance, in the example below, whenever the module named jq is required, jquery is loaded instead. The asterisk means that the substitutions are good everywhere.
Your configuration should look like this:
requirejs.config({
baseUrl: "assets/js/",
paths: {
"jquery" : "lib/jquery/jquery",
// ...
"backbone" : "lib/marionette/backbone",
"backbone.radio" : "lib/marionette/backbone.radio",
"marionette" : "lib/marionette/backbone.marionette",
// ...
},
map: {
"*": {
jq: "jquery",
bb: "backbone",
bbr: "backbone.radio",
mt: "marionette"
}
},
shim: {
// whatever shims are appropriate
}
});

Related

WHat would be a proper way to require modules

Consider the following requirejs config:
requirejs.config({
waitSeconds: 10,
baseUrl: 'js/libs',
paths: {
'jQuery' : 'jquery',
'jQueryUi' : 'jquery.ui',
'cookie' : 'jquery.cookie',
'underscore' : 'underscore',
'backbone' : 'backbone',
'text' : 'text',
'reusable' : '../../tmpl/reusable.tmpl.html'
},
shim: {
'jQuery':{
exports: '$'
},
'cookie':['jQuery'],
'jQueryUi':['jQuery'],
'underscore': {
exports: '_'
},
'backbone':{
deps: ['underscore'],
exports: 'Backbone'
}
}
});
require(['cookie','jQueryUi'],function(){
require(['backbone'],function(){
this._templates = {};
require(['text!reusable'],function(reusable){
this._templates['reusable'] = reusable;
});
});
});
Everything works as expected so far...
Contents of some_module.js:
define(function(){
var init = function(){
console.log('some_module initialized');
};
return{
init:init
};
});
Based on the Backbone router navigate function, some_module is required at a certain point like so:
require(['some_module'],function(module){
module.init();
});
On route change, a similar module is called the same way.
When navigating, the user may return to the previous route, meaning that some_module is requested again, this time from the cache since some_module.js was stored there on the first call.
Question:
Since some_module can be requested once, or multiple times, is it a good practice to load the module every time, even if the file is cached ?... or initially set it in the global scope:
var some_module = require('some_module');
and each time the module is needed, just call:
some_module.init()
or whatever property it may return?
What would be the difference when it comes to memory leaks, and general application functionality?
The general rule is that everything you load through RequireJS is loaded once and only once.
The first time the module is needed (due to require or a define that has the module as a dependency), it will be actually fetched from the network and then its factory function will be executed. (The factory is the function that you give to define.) The result of the factory function is cached by RequireJS.
When the module is needed again, the module is returned from RequireJS cache without using the browser's cache of files or going to the network.

RequireJS - How to configure Underscore before it's loaded by Backbone?

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

Properly loading webshims / modernizr with requirejs?

I have modernizr / pollyfiller included at the top of my index.html file, and in my main.js:
require.config({
paths : {
'jquery' : 'lib/jquery-1.10.2.min',
'jqdate' : 'lib/jquery.dateFormat-1.0',
'webshims' : 'lib/polyfiller'
},
shim : {
'lib/underscore' : {
exports : '_'
},
'lib/backbone' : {
deps : ["lib/underscore", "jquery"],
exports : 'Backbone'
},
"modernizr" : {
deps : ["jquery"],
exports : "modernizr"
},
"webshims" : {
deps : [ "jquery", "lib/modernizr-custom"],
exports: "webshims"
}
}
});
var router, vent;
require(["jquery", "lib/underscore", "lib/backbone", "app", "lib/modernizr-custom", "webshims"], function($, _, Backbone, Router, modernizr, webshims) {
$(function() {
$.webshims.setOptions('forms forms-ext', {
replaceUI : false,
waitReady : false
});
$.webshims.polyfill('forms forms-ext');
router = new Router();
vent = _.extend({}, Backbone.Events);
$.expr.cacheLength = 1;
Backbone.history.start({
});
});
});
This will generally load fine, however, sometimes it looks like webshims is not defined by the time I try to call:
$.webshims.setOptions('forms forms-ext', {
replaceUI : false,
waitReady : false
});
$.webshims.polyfill('forms forms-ext');
and I get the error: TypeError: $.webshims is undefined
Is there a better way to load this?
edit
So, I updated the script like you said, and had to capitalize Webshims in the paths and shim definition. It loads fine but now I get an error:
Uncaught SyntaxError: Unexpected token <
in Chrome and
SyntaxError: syntax error
<!DOCTYPE html>
in firefox
Updated Answer
Alexander Farkas pointed out in a comment that polyfiller defines itself as "polyfiller" like this:
define('polyfiller', ['jquery'], factory);
So:
No shim should be required to load polyfiller.js.
The module defined by polyfiller.js should always be referred to as "polyfiller". So there has to be a paths setting that maps the module name polyfiller to the actual path of the polyfiller.js file.
So the original config should be modified to remove the "webshims" shim, then the paths setting "webshims": "lib/polyfiller" should become "polyfiller": "lib/polyfiller" and the require call should be:
require(["jquery", "lib/underscore", "lib/backbone", "app", "lib/modernizr-custom", "polyfiller"], function($, _, Backbone, Router, modernizr) {
I've dropped the last variable from the function's parameters because there's no need to pass the module value since the polyfiller.js file registers itself as $.webshims.
This is similar to how jQuery defines itself as "jquery" (it needs no shim and is always called "jquery").
Original Answer
Change your require call so that you require "webshims" instead of "lib/polyfiller":
require(["jquery", "lib/underscore", "lib/backbone", "app", "lib/modernizr-custom", "webshims"], ...
The code in your question shows you've set the paths configuration option so that the module name "webshims" resolves to "lib/polyfiller", and created what looks like a sensible shim for it. However, when you require the webshims module you refer to it as "lib/polyfiller". RequireJS does not do a reverse resolution to figure out that "lib/polyfiller" is "webshims".
Alternatively, you could drop the "webshims" name from paths and rename the shim so that it is set for "lib/polyfiller". However, I consider it to be a better practice to refer to 3rd party libraries by one-word names throughout an application rather than have paths for them. So "jquery", "bootstrap", "underscore", and "webshims" etc. rather than "lib/...".

Using Angular with breeze and require

i am trying to use angular with breeze and requireJS
how ever i am getting error of
Uncaught Error: Module name "ko" has not been loaded yet for context: _. Use require([])
i have configured
define("breezeConfig", ["breeze"], function(breeze) {
// configure to use the model library for Angular
//breeze.config.initializeAdapterInstance({ dataService: "OData" });
breeze.config.initializeAdapterInstance("modelLibrary", "backingStore", true);
// configure to use camelCase
breeze.NamingConvention.camelCase.setAsDefault();
var serverAddress = "/odata/";
var manager = new breeze.EntityManager(serverAddress);
return breeze;
});
and in the main module
require.config({
baseUrl: "/app",
paths: {
"jQuery": "lib/jquery-1.8.2",
"angular": "lib/angular",
"angular-resource": "lib/angular-resource",
"text": "lib/text",
"Q": "lib/q",
"breeze": "lib/breeze.min"
and so on
at the end
require([
'jQuery',
'Q',
'breeze',
'angular',
'app',
'controllers',
'routes',
'breezeConfig'
], function ($, angular, app) {
angular.element(document).ready(function () {
angular.bootstrap(document, ['AMail']);
});
where am i wrong?
Yes ... we know. It's been reported on S.O. before. We have a fix on the way (next release).
Meanwhile, inside your main module do two things:
1) define a bogus knockout module
define('ko', function() {}); // do nothing
2) add a shim to your require.config function:
...
shim: {
jquery: { exports: '$' },
angular: { exports: 'angular' },
breeze: { deps: ['ko', 'jquery', 'Q'] }
}
...
You'll need the shim (minus the 'ko' dependency!) even after we fix the ko problem. Breeze depends on 'jquery' and 'Q' which must be loaded first. You may or may not need the other shim lines.

Requirejs2: How to handle own files?

I have configured requirejs to load the core libs (jquery, underscore, backbone).
Now I would like to add my backbone models, controllers, views, etc to be loaded asyncronly
I found a lots of tutorials to this topic and lots of "ready" boilerplates unfortunatly I mentioned that most approaches are depreceated or rather complicated (even there are better approaches).
One example is how I configured requirejs for the main libs:
https://stackoverflow.com/a/10914666/1309847
So how do I load Backbone Views, Models, Collections, Routers, Controllers and Templates with a simple and valid Requirejs configuration?
I followed youre advice but get some strange error
main.js
require.config({
paths: {
jquery: 'vendors/jquery/jquery',
underscore: 'vendors/underscore/underscore',
backbone: 'vendors/backbone/backbone'
},
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
}
}
});
require(['app'], function(app){
});
app.js
define(['jquery', 'underscore', 'backbone'], function($, _, Backbone){
var Message = new Backbone.Model.extend({
//idAttribute: '_id',
//defaults: { body: '' }
//url: function(){ return this.id ? '/messages/' + this.id : '/messages'; }
});
var newMessage = new Message({ body: 'hi' });
newMessage.save();
});
The error occours in app.js:
Uncaught TypeError: Object [object Object] has no method 'apply'
When I comment the new Backbone.Model.extend part I don't get any error anymore.
in my experience, the best way to bootstrap your application is by creating a Backbone.Router. So you can associate urls with your application functionality.
If you are using RequireJS+Backbone, you probably have a main.js where RequireJS is configured (paths, shims, etc). The first call to "require" is used to load a initial script in order to bootstrap the whole app.
For example:
/**
* main.js - RequireJS bootstrap
*/
require.config({
paths: {
//your paths
},
shim: {
//your shims
}
});
require(
[
'app' //app.js is at the same directory as main.js
],
function(app) {
app.init();
}
);
then in app.js you can create a new Router instance, or you can just start creating Views and Models.
For further reference: http://addyosmani.github.com/backbone-fundamentals/
So as I have now understood right: You have to wrap a requirejs function around youre own custom js file.
The function is called define. The first parameter is an array of the dependencies which you have defined in the main.js file or a relative path to another custom js from you.
The second parameter is the callback which holds the original file. Important is that you return the object, function, array or variable which you want to share.
The whole thing looks like this:
define(
['underscore', 'backbone'], // the dependencies (either relative paths or shortcuts defined in main.js
function(_, Backbone){ // the return statement of the deps mapped to a var
var MessageModel = Backbone.Model.extend({ // the original code, file
defaults: { body: '' },
initialize: function(){}
});
return MessageModel; // the return statement, sharing the "final result", sometimes you return the initialize parameter
});
The same for a collection wrapping the models:
define(
['jquery', 'underscore', 'backbone', 'models/message_model'], // deps and the last one is the relative path
function($, _, Backbone,MessageModel){ // same as above explained
var MessageCollection = Backbone.Collection.extend({
model: MessageModel,
initialize: function(){}
});
return MessageCollection;
});
I now only have to figure out how I can bootstrap to whole application. But I think I need more knowledge of backbone to do this :)

Resources