20% of the time, the scripts fail loading while using RequireJS.
The additional files that I am using throu the application require, besides the JS libraries, the base.js file, which contains configurations and some setup for underscore & backbone. Without these settings, the other files won't work.
The script tag in the is the following:
<script data-main="http://*path*/js/common" src="http://*path*/js/lib/require.js"></script>
The common.js file is
requirejs.config({
shim: {
underscore: {
exports: "_"
},
backbone: {
deps: ["jquery", "underscore"],
exports: "Backbone"
},
base: {
deps: ["backbone"]
}
},
paths: {
jquery: [
'//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min',
'http://*path*/media/admin/js/lib/jquery.min'
],
base: 'http://*path*/media/admin/js/base',
backbone: 'http://*path*/media/admin/js/lib/backbone',
underscore: 'http://*path*/media/admin/js/lib/underscore'
}
});
The base.js file, with the settings for backbone, underscore and jQuery, contains:
define(['jquery', 'backbone', 'underscore'], function(jQuery, Backbone, _) {
//CODE
return var;
});
And the other files contain
define(['base'], function(var) {
//CODE
});
In the page I am loading the files using:
require(['common'], function() {
require(['page/file'], function() {
//CODE
});
});
What am I doing wrong, why jQuery, underscore and backbone fail loading sometimes and how can I fix this?
The error message is:
GET http://*host*/backbone.js 404 (Not Found) require.js:1
Uncaught Error: Script error for: backbone
http://requirejs.org/docs/errors.html#scripterror
I don't know that this is the only problem but this shim should be removed:
base: {
deps: ["backbone"]
}
You've shown a base.js file that calls define. The rule is simple: if your module calls define, then you use define to set dependencies, and the return value of the function you pass to define to set the value of your module; if your module does not call define, then you need a shim to set dependencies and determine the value of the module (if needed).
Related
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
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
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 this url:
"localhost/app2/app.html"
I would expect require.js to manipulate the paths so that all scripts it loads are prefixed with the context 'app2/'. However, I get a 404 for my app script, and when I look in firebug the browser is trying to retrieve it without the app2 context.
My file structure is:
content
|-app.html
|-main.js
|-app
|-app.js
|-main.js
|-libs
|-require.js
In app.html I have a single script tag:
<script src="libs/require.js" data-main="app/main" type="text/javascript"></script>
The main.js file has this:
require.config({
baseUrl: "/",
paths: {
xx: "app/app",
header: "app/views/header",
footer: "app/views/footer",
templates: "app/views/templates",
jquery: "libs/jquery-2.0.3",
k: "libs/kendo/kendo.core",
backbone: "libs/backbone",
marionette: "libs/backbone.marionette",
wreqr: "libs/backbone.wreqr",
babysitter: "libs/backbone.babysitter",
underscore: "libs/underscore",
text: "libs/text"
},
shim: {
jquery: {
exports: '$'
},
underscore: {
exports: '_'
},
backbone: {
deps: ['jquery', 'underscore'],
exports: 'Backbone'
},
marionette: {
deps: ['jquery', 'underscore', 'backbone'],
exports: 'Marionette'
}
}
});
require(["xx"], function (app) {
app.start();
});
And my app.js looks like this:
define(['jquery', 'underscore', 'backbone', 'marionette'],
function ($, _, Backbone, Marionette) {
var app = new Backbone.Marionette.Application();
app.addRegions({
headerRegion: "#header-region",
moduleRegion: "#module-region",
footerRegion: "#footer-region",
dialogsRegion: "#dialogs-region"
});
app.on("initialize:after", function() {
console.log("Starting App");
Backbone.history.start();
});
return app;
});
So, when I hit the url in the browser I see the app.html file is loaded first, then require.js is loaded followed by main.js. After that I get a 404 trying to load app.js from localhost/app/app.js -- the app2 context is missing.
I have tried renaming the files, in case require is getting confused (didn't work), and I have tried moving the xx path up and down in the list to see if it's a positional bug (it's not). I have tried using a path for xx starting with ./, and that doesn't work either. I have navigated to the app.js with the browser, on the expected path, and it is happily served by my http server.
At first I thought that this was a path problem, so I read the solutions here on stackoverflow, but it's not a simple path problem, because it is the context that's missing -- the root url -- not the path. AHGA.
Ok, I have the answer. I had set the baseUrl to an absolute URL, rather than relative. The correct string is:
baseUrl: './'
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();
});