This question already has an answer here:
requirejs - what export exactly do here?
(1 answer)
Closed 9 years ago.
I am new to RequireJS and wa just going through the following configuration code;
({
appDir: "../",
baseUrl: "js",
dir: "../../appdirectory-build",
paths: {
jquery: 'libs/jquery/jquery-1.8.2',
underscore: 'libs/underscore/underscore-1.4.4',
backbone: 'libs/backbone/backbone-0.9.10',
templates: '../templates',
app: 'app'
},
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
}
},
modules: [
{
name: "main"
}
]
})
I did not understand what exactly is the "shim" used for?
Could someone please explain me in simple terms.
You can define non modular old scripts using shim config. By the non modular I mean the scripts those don't declare there dependencies using define(). So in the shim config in the above example you mention to load underscore and export it as '_' that means when the underscore is loaded it is accessible using _ in your application. And for backbone it means that before loading backbone, shim should ensure that underscore and jquery are loaded prior to backbone. Because underscore and jquery are the dependencies of the backbone, so shim is helping managing your dependencies of non modular scripts. After loading backbone export it as "Backbone" in your application.
Related
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'm trying to include jsjws in my current project (Backbone, Marionette) which uses RequireJS to include all modules. I have AMD and non AMD scripts included, the non AMD using shims but I'm not sure how jsjws (http://kjur.github.io/jsjws/) will work in this instance. Maybe someone can help?
Current RequireJS config with attempt at including jsjws:
paths: {
backbone: "vendor/backbone", "backbone.syphon":"vendor/backbone.syphon",
jquery: "vendor/jquery",
json2: "vendor/json2",
underscore: "vendor/underscore",
marionette: "vendor/backbone.marionette",
jsjws: "vendor/jws-3.0",
tpl: "vendor/tpl"
},
shim: {
underscore: {
exports: "_"
},
backbone: {
deps: ["jquery", "underscore", "json2"],
exports: "Backbone"
},
"backbone.syphon": ["backbone"],
marionette: {
deps: ["backbone"],
exports: "Marionette"
}
}
many thanks,
Wittner
Looking at the code for jsws and at the documentation, it seems to me that this is what you need to add to your shims:
jsjws: {
exports: "KJUR"
}
Or I believe you could have it export "KJUR.jws" to skip the top level namespace (which seems useless in this context).
I was not able to find a clear list of what dependencies it has. If I look at the various samples in the github repo, the list of files loaded before jsjws seems to vary quite a bit depending on the specific needs of the project. At any rate, whatever your project needs for jsjws to do its job would have to be added to a deps field, and probably these dependencies would get shims of their own.
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.
Here's my situation, using Backbone and Handlebars with Requirejs.
I'm following CommonJS module definition style, because I find myself to be more comfortable with it:
define(function(require) {
var Backbone = require('Backbone')
var Item = require('model/item')
// ...
})
And this is my requirejs config:
require.config({
baseUrl: "/javascripts/",
paths: {
jquery: 'components/jquery/jquery',
underscore: 'components/underscore/underscore',
backbone: 'components/backbone/backbone',
handlebars: 'components/handlebars/handlebars',
text: 'components/text/text'
},
shim: {
underscore: {
exports: "_"
},
handlebars : {
exports: "Handlebars"
},
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
}
}
});
Everything is running smooth before optimization, no problem occurs.
But, after optimization with r.js dependencies seem to break.
I'd like to use Almond js in production, so here's my build file:
({
baseUrl: ".",
paths: {
jquery: "components/jquery/jquery",
underscore: "components/underscore/underscore",
handlebars: "components/handlebars/handlebars",
backbone: "components/backbone/backbone",
text: "components/text/text"
},
// we use almond minimal amd module loader
name: "components/almond/almond",
// the application entry point
include: ['app/init'],
// we need to teel almond to require app/init
insertRequire: ['app/init'],
out: "main.js",
cjsTranslate: true,
wrap: true,
optimize: "none"
})
Now, when I run the optimized javascript in browser, all I get are error messages, saying me that jQuery and Handlebars are undefined (neither Backbone.$ is, of course).
A simple workaround was to force jQuery loading, and assigning it to Backbone, like this:
var $ = require('jQuery')
var Backbone = require('Backbone')
Backbone.$ = $
But it sounds very silly and redundant to me.
I feel like I'm doing something wrong but cannot figure out what.
After optimization Handlebars fail to load as dependency too.
If I force its loading (as I did with jQuery), I get an error message during the build process, saying me that the module fs (a npm package) cannot be found.
I googled but found only this topic on Google groups (https://groups.google.com/forum/?fromgroups=#!topic/requirejs/lYwXS-3qjXg) that seems to be related to my problem, even if proposed solutions are not working at all.
I think you should add the Shim's config in your build file too.
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();
});