Related
I recently worked on a web app, and i wanted to separate it into modules.
I searched and found out that RequireJs is the best for this. I read the doc, and some tutorials about it and came up with this
requirejs.config({
baseUrl: "js/lib",
shim: {
'jquery-1.12.1.min': ['jquery-1.12.1.min'],
'materialize.min': ['materialize.min'],
'knockout-3.4.0': ['knockout-3.4.0'],
'pouchdb-5.3.0.min': ['pouchdb-5.3.0.min']
},
waitSeconds: 0,
paths: {
'jquery-1.12.1.min': 'jquery-1.12.1.min',
'materialize.min': 'materialize.min',
'knockout-3.4.0': 'knockout-3.4.0',
'pouchdb-5.3.0.min': 'pouchdb-5.3.0.min',
}
});
require(["jquery-1.12.1.min", "knockout-3.4.0", "materialize.min", "pouchdb-5.3.0.min"], function($, ko) { //My main functions and other stuff ... }
My index has the following:
<script data-main="js/main" src="js/lib/require.js"></script>
<script type="text/javascript" src="js/converter.js"></script>
But it seems that my Jquery, KO, materialize.css and pouchdb aren't loading as i see on my chrome dev tools in Network:
I also read about the shim config how to set up the dependences and i want them in that order. I don't really know what am i missing, any help would really be appreciated.
Folder structure is:
js:
lib:
->jquery-1.12.1.min.js
->knockout-3.4.0.js
->pouchdb-5.3.0.min.js
->materialize.min.js
->require.js
main.js
converter.js
Ok it seems require and materialze.css have a problem with hammer.js, what i recommend is you go and download Hammer.min.js and include it in your lib folder.
Then in your main.js add the following:
requirejs.config({
baseUrl: 'js/lib',
waitSeconds: 0,
paths: {
app: '../app',
jquery: 'jquery-1.12.1.min',
materialize: 'materialize.min',
knockout: 'knockout-3.4.0',
pouchdb: 'pouchdb-5.3.0.min',
hammer: 'hammer.min'
},
shim: {
hammer: {
deps: ['jquery']
},
pouchdb: {
deps: ['jquery']
},
knockout: {
deps: ['jquery'],
exports: 'ko'
},
materialize: {
deps: ['jquery', 'hammer'],
},
jquery: {
exports: '$'
}
}
});
You include you hammer and also the dependency for jquery on it. And i see that you didn't put the PouchDb object in the function:
define(["jquery", "knockout", "pouchdb", "materialize" ], function($, ko, PouchDB) {...
Hope this helps
Using path, requirejs replace module id prefixes (name in config) with the corresponding value.
Using shim you can export a global variable and configure the dependencies ( materialize depends jquery so you have to import jQuery before importing materialize.js )
requirejs.config({
baseUrl: "js/lib",
waitSeconds: 0,
paths: {
'jquery': 'jquery-1.12.1.min',
'materialize': 'materialize.min',
'knockout': 'knockout-3.4.0',
'pouchdb': 'pouchdb-5.3.0.min',
'hammer': 'hammer.min',
},
shim: {
pouchdb: {
deps: ['jquery']
},
knockout: {
exports: 'ko'
},
materialize: {
deps: ['jquery', 'hammer']
},
jquery: {
exports: '$'
}
}
});
require(["jquery", "knockout", "materialize", "pouchdb"], function ($, ko) {
console.log($);
console.log(ko);
});
I have the following directory structure to my tpl:
-src
-assets
-js
-lib
[files]
-src
-templates
-common
builder_regions.tpl
My require.config is:
require.config({
baseUrl:'src/assets/js',
paths: {
backbone: 'lib/backbone',
jquery: 'lib/jquery.min',
'jquery-ui': 'lib/jquery-ui-1.10.4.custom.min',
underscore: 'lib/underscore.min',
modernizr: 'lib/modernizr.min',
'magnific-popup': 'lib/magnific-popup.min',
text: 'src/assets/jslib/text',
marionette: 'lib/backbone.marionette.min',
tpl: 'lib/underscore-tpl'
},
shim: {
jquery: {
exports: '$'
},
underscore: {
exports: '_'
},
backbone: {
deps: [ 'jquery', 'underscore' ],
exports: 'Backbone'
},
marionette: {
deps: [ 'jquery', 'underscore', 'backbone' ],
exports: 'Marionette'
},
'jquery-ui': {
deps: [ 'jquery' ],
exports: '$ui'
},
'magnific-popup': {
deps: [ 'jquery' ],
exports: 'magnificPopup'
},
tpl: [ 'text' ]
}
});
My require module is set-up as:
define([ 'tpl!src/templates/common/builder_regions.tpl', function( Marionette, layoutTpl ) {
console.log( 'did not throw' );
});
When I access the module I get the following error:
GET http://localhost:3000/src/assets/js/src/tpl.js 404 (Not Found)
Why is file tpl.js being referenced when I provided the path in require.config? Thanks!
If your underscore-tpl.js is this one then you do not need a shim configuration for it because it calls define by itself. If you use a shim configuration for something that does not need a shim, RequireJS can behave strangely.
Another thing not related to the problem you are reporting here but could give you trouble down the line: jQuery has not needed a shim since at least version 1.9. So if you use a version that is >= 1.9, you should remove the shim you have for jquery.
Try This:
define(['marionette', 'tpl!src/templates/common/builder_regions.tpl'], function( Marionette, layoutTpl ) {
console.log( 'did not throw' );
});
I'm trying to get Masonry loaded into my app using RequireJS, but it keeps causing backbone to spit out a "object is not a function" error anytime I add it.
Edit: possibly related to this issue.
main.js
require.config({
paths: {
jquery: 'lib/jquery-1.9.1',
underscore: 'lib/underscore-1.5.2',
backbone: 'lib/backbone-1.0.0',
masonry: 'lib/masonry.pkgd'
},
shim: {
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
underscore: {
exports: '_'
}
}
});
require(['app'], function(App){
App.initialize();
});
app.js
define([
'jquery',
'underscore',
'backbone',
'masonry',
'collections/ideas',
], function($, _, Backbone, Masonry, IdeasCollection) {
var IdeasView = Backbone.View.extend({
el: $('#container'),
initialize: function() {
...
},
render: function(){
...
}
});
return IdeasView;
});
To use Masonry as a jQuery plugin with RequireJS, you’ll need to run jQuery bridget.
Check the documentation:
http://masonry.desandro.com/appendix.html#requirejs
You can download bridget here:
https://github.com/desandro/jquery-bridget
Then you can include an run bridget and it should work fine
define([
'jquery'
, 'underscore'
, 'backbone'
, 'config'
, 'app'
, 'jquery.masonry'
, 'jquery.bridget'
], function ($, _, Backbone, Config, App, Masonry, bridget) {
initialize : function () {
bridget('masonry', Masonry);
}
});
Hope it helps!
This is one way you can run it without bridget:
requirejs-config.js:
var config = {
paths: {
"lib-masonry": "Module/js/lib/masonry.pkgd.min"
},
shim: {
"lib-masonry": {
deps: ['jquery', 'jquery/ui']
}
}
}
and then in another module where you want to use it:
define([
'jquery',
'lib-masonry'
], function ($, Masonry) {
$.widget('ModuleNamespace.containerMasonry', {
options: {
},
_create: function() {
var msnry = new Masonry('.grid', {
itemSelector: '.grid__item',
columnWidth: 200
});
// .. code
}
});
return $.ModuleNamespace.containerMasonry;
});
I am trying to use the backbone-ui library but cannot figure out the require.js configuration to get the modules loaded.
main.js:
requirejs.config({
baseUrl: '/static/js/facebook_report_app/js',
paths: {
backbone: 'lib/backbone'
, underscore: 'lib/underscore'
, jquery: 'lib/jquery'
, laconic: 'lib/laconic'
, moment: 'lib/moment'
, backboneUI: 'lib/backbone-ui/js/backbone_ui'
, menuUI: 'lib/backbone-ui/js/menu'
, textUI: 'lib/backbone-ui/js/text_field'
, text: 'lib/text'
},
shim: {
'lib/underscore': {
exports: '_'
},
'laconic': {
deps: ["jquery"],
exports: "$.el"
},
'lib/backbone': {
deps: ['lib/underscore']
, exports: 'Backbone'
},
'backboneUI': {
deps: ['lib/backbone', 'laconic', 'jquery']
, exports: 'Backbone.UI'
},
'textUI': {
deps: ['jquery', 'lib/backbone', 'backboneUI', 'laconic']
, exports: 'Backbone.UI.TextField'
},
'menuUI': {
deps: ['lib/backbone', 'backboneUI', 'laconic', 'textUI']
, exports: 'Backbone.UI.Menu'
},
'lib/backgrid': {
deps: ['lib/underscore', 'lib/backbone']
, exports: 'Backgrid'
},
'report_app': {
deps: ['lib/underscore', 'lib/backbone', 'lib/backgrid', 'backboneUI']
}
}
});
require([
'facebook_report_app'
],
function(FacebookReportApp) {
window.fbReport = new FacebookReportApp();
});
menu_user.js
define(['jquery', 'lib/backbone', 'backboneUI', 'menuUI', 'laconic'], function(AccountPickerView) {
var AccountPickerView = Backbone.UI.Menu.extend({
el: '.left-nav',
});
return AccountPickerView;
});
When I load this in dev, the console reports "Object [object Object] has no method 'input' ", on line 44 of the text_field.js of the Backbone-UI library.
I suppose my configuration approach is broken to begin with -- I added the menu.js and text_field.js files bc I was getting errors 'Backbone.UI.Menu' and Backbone.UI.TextField' (a requirement of Menu) weren't defined. But there must be a cleaner way to bring in the various files of backbone-ui.
So how do I get rid of the 'no method input' error? Or better configure to use Backbone UI? Or should I be using jQuery UI in the first place? In which case, where do I go to figure out configuration of that?
I got it working, after much fiddling with the following setup:
js/main.js
requirejs.config({
baseURL: 'js',
urlArgs: "bust=" + (new Date()).getTime(),
shim: {
underscore: {
exports: '_'
},
jquery: {
exports: '$'
},
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
laconic: {
exports: '$.el'
},
backbone_ui: {
deps: ['underscore', 'jquery', 'backbone', 'laconic', 'moment'],
exports: 'Backbone.UI'
}
},
paths: {
jquery: 'http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min',
moment: './lib/moment.min',
laconic: './lib/laconic',
underscore: 'http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min',
backbone: 'http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min',
backbone_ui: './lib/backbone-ui',
crypto: 'http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5',
templates: '../templates',
collections: './collections',
models: './models',
}
});
js/views/json.js
define(['jquery','underscore', 'backbone', 'backbone_ui'],
function($,_,Backbone, BBUI){
var JsonView = Backbone.View.extend({
className: "json-item",
initialize: function(data){
var self = this;
this.app = data.app;
this.model = data.model;
this.listenTo(this.model, "change", function(){
console.log("model changed", self.model);
});
this.model.fetch({
success: function(){
self.render();
}
});
},
render: function(){
var self = this;
$(this.el).empty();
for (key in this.model.attributes){
this.el.appendChild(new Backbone.UI.Label({content:key}).render().el);
this.el.appendChild(new Backbone.UI.TextField({model: this.model, content:key}).render().el);
}
this.el.appendChild(new Backbone.UI.Button({content:"save", onClick: function(){self.model.save()}}).render().el);
return this;
}
});
return JsonView;
});
Please note that I import backbone-ui as BBUI and never reference it that way. BBUI.TextField() is a defined function and using it would work as well, but the way Backbone-ui is set up it makes alterations to Backbone, Jquery, and Underscore when it loads. So I figured I just needed it to be run prior to the view getting loaded.
I'm trying to use both Underscore and Underscore.string with RequireJS.
Contents of main.js:
require.config({
paths: {
'underscore': '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min',
'underscore-string': '//cdnjs.cloudflare.com/ajax/libs/underscore.string/2.3.0/underscore.string.min',
},
shim: {
'underscore': {
exports: '_'
},
'underscore-string': {
deps: ['underscore'],
exports: '_s'
},
}
});
var modules = ['underscore-string'];
require(modules, function() {
// --
});
Browser sees the _, but doesn't see the _s - it is undefined.
Ideally i want to have Underscore under _ and Underscore.string under _.str, but _ and _s are fine too. How can i do that?
Versions: RequireJS 2.1.5, Underscore 1.4.4, Underscore.string 2.3.0
Note: Thanks to #jgillich make sure, that paths have two slashes (//cdnjs.cloudfare.com/...), otherwise the browser would think that URL is relative to the server, and Firebug will throw:
Error: Script error
http://requirejs.org/docs/errors.html#scripterror
I found the error. For some reason RequireJS doesn't work with version of Underscore.string from cdnjs.com, so i replaced it with Github version. I guess it has something to do with the commit 9df4736.
Currently my code looks like the following:
require.config({
paths: {
'underscore': '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min',
'underscore-string': '//raw.github.com/epeli/underscore.string/master/dist/underscore.string.min',
},
shim: {
'underscore': {
exports: '_'
},
'underscore-string': {
deps: ['underscore'],
},
}
});
var modules = ['underscore', 'underscore-string'];
require(modules, function(_) {
// --
});
Underscore.string resides in _.str.
Edit: As of 16 July 2013 the CDNJS version is updated with the upstream.
Battling with this for hours before i understand what i was doing wrong
This is what i did wrong
You should not rename the file underscore.string in main.js
even though in my library i did rename the file in paths i name it back to 'underscore.string'
This is how your main.js should look like
require.config({
paths: {
underscore: 'lib/underscore',
'underscore.string' : 'lib/_string' ,
},
shim: {
underscore: {
exports: '_',
deps: [ 'jquery', 'jqueryui' ]
},
'underscore.string': {
deps: [ 'underscore' ]
},
}
....
You could then either add it as dependency with in your shim like i did for my mixin file
shim: {
mixin : {
deps: [ 'jquery', 'underscore', 'underscore.string' , 'bootstrap' ]
},
Or just define it in your different pages like
/*global define */
define([
'underscore.string'
], function ( ) {
it just work now you can access it through _.str or _.string
This is why you should do it this way and not try to name it something else
on line 663 of underscore.string.js
// Register as a named module with AMD.
if (typeof define === 'function' && define.amd)
define('underscore.string', [], function(){ return _s; });
Which means that it will only register it with AMD require JS if you are defining 'underscore.string'
works for my ONLY if I use exact "underscore.string" module name in shim. Seems related to hardcoded name in underscore.string itself
Exempt from underscore.string source code (this branch is executed when require used):
// Register as a named module with AMD.
if (typeof define === 'function' && define.amd)
define('underscore.string', [], function(){ return _s; });
So for me the only working configuration is:
require.config({
paths: {
'underscore': '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min',
'underscore.string': '//raw.github.com/epeli/underscore.string/master/dist/underscore.string.min',
},
shim: {
'underscore': {
exports: '_'
},
'underscore.string': {
deps: ['underscore'],
},
}
});
var modules = ['underscore', 'underscore.string'];
require(modules, function(_) {
// --
});
Here's a working code using Requirejs "order" plugin, also includes Jquery, and everything loads without any conflict:
requirejs.config({
baseUrl: "assets",
paths: {
order: '//requirejs.org/docs/release/1.0.5/minified/order',
jquery: 'http://code.jquery.com/jquery-2.1.0.min',
underscore: '//underscorejs.org/underscore-min',
underscorestring: '//raw.githubusercontent.com/epeli/underscore.string/master/dist/underscore.string.min',
underscoremixed: 'js/underscore.mixed' // Create separate file
},
shim: {
underscore: { exports: '_' },
underscorestring: { deps: ['underscore'] }
}
});
require(['order!jquery','order!underscoremixed'], function($,_) {
// test
console.log( _.capitalize('capitalized text') );
});
Inside js/underscore.mixed.js put the following...
define(['underscore','underscorestring'], function() {
_.mixin(_.str.exports());
return _;
});
Cheers! :)