What does requirejs.config() do? - javascript

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

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

RequireJS doesn't always load modules

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).

load javascript file before onload with requirejs

I would like to use requireJS. However, I have a lib that needs to be loaded before the DOM. However, this is not what happens with requireJS
<html>
<head>
<script data-main="/app" src="/require.js"></script>
</head>
<body>
<bar-foo/>
</body>
</html>
With app.js
require.config({
paths: {
'customElement': '/customElement',
'barfoo': '/barfoo'
},
shim: {
barfoo: {
deps: [ 'customElement' ]
}
}
});
define(['barfoo'], function() {
....
}
For example, if I simply load this script directly in the head (without requireJS) it works fine. Is there a require-config-option so I can load a specific file immediately (synchronously?) ?
Requirejs is known for it's asynchronous power. However when you need some sort of an order in which you want files to be loaded due to dependencies, in require.config there is a shim config:
shim: 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.
So let's say you have a backbone app that depends on Underscore and jQuery, and you want them to load in that order then your would:
require.config({
paths: {
'Backbone': '/Backbone',
'Underscore': '/Underscore',
'jQuery': '/jQuery'
},
shim: {
'Backbone': [ 'Underscore', 'jQuery' ]
}
});
require(['Backbone'], function(Backbone){
//.....
});
So, RequireJS allows us to use the shim config to define the sequence of files which need to be loaded in correct order.

Can I set a different path for a child dependency in the require.config?

I have two problems that are related to each other.
The first is that I want to have a folder named backbone, and that collides with having backbone as a short name for the library in the path. It seems that RequireJS thinks that backbone/model/User is a child of the backbone library or something. Solution, name the library Backbone with capital B.
The second problem is that I'm using ModelBinder, which has "backbone" as a dependency. Solution, change the minified file.
Both solutions seems like a bad hack for not doing something right in RequireJS configuration, but I cant figure out what I'm doing wrong.
My public folder structure is something like:
public/
js/
backbone/
model/
...
view/
...
vendor/
backbone.min.js
Backbone.ModelBinder.js
...
common.js
My common.js has something like this:
require.config({
baseUrl: "/js",
shim: {
'underscore': {
exports: '_'
},
"Backbone" : {
deps: ["underscore", "jquery"],
exports: 'Backbone'
}
},
paths: {
underscore: 'vendor/underscore.min',
jquery: 'vendor/jquery',
model_binder: 'vendor/Backbone.ModelBinder',
Backbone: 'vendor/backbone.min'
}
});
So my two questions are: How can I keep Backbone.ModelBinder as it is, and tell requirejs that when that library ask for backbone, its asking for js/vendor/backbone.min.js without "polluting" my global paths.
And why can't I use both backbone (lowercase b) in the path and have the directory?
One solution (yes, not so sane) is to include paths definitions for every directory under js/backbone, i.e.:
require.config({
...
paths: {
...
backbone: 'vendor/backbone.min', // NOTE lower-case 'b', as desired
"backbone/model": "backbone/model",
"backbone/view": "backbone/view",
... // and so on
}
});
This also means that there is no module directly under js/backbone.
An alternative would be to keep the capital 'B' in the module name for Backbone and use the map config for the Backbone.ModelBinder.js:
require.config({
...
paths: {
...
Backbone: 'vendor/backbone.min' // NOTE capital 'B' again
},
map: {
"model_binder": {
"backbone": "Backbone"
}
});
Thinkng retrospectively, the map can be applied to all modules so that whenever they request "backbone" (lower-case 'b') you deliver "Backbone":
require.config({
...
paths: {
...
Backbone: 'vendor/backbone.min' // NOTE capital 'B' again
},
map: {
"*": { // <------ Here difference form code above
"backbone": "Backbone"
}
});
Now anyone can ask for "backbone" and get Backbone, or "backbone/model/User" (or "backbone/module") and get the corresponding module.

Loading Backbone and Underscore using RequireJS

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

Categories

Resources