How to load backbone-deep-model with RequireJS? - backbone.js

While backbone-deep-model has AMD support for use with RequireJS, it depends on an underscore mixin in an external file called underscore.mixin.deepExtend.js that is not AMD compatible.
Looking at this question: How to mixin Underscore plugins in RequireJS?, it seems that I can manually mixin deepExtend into Underscore within the shim init setting in RequireJS.
...
shim: {
...
'deep-model': {
deps: 'underscore',
init: function() {
_.mixin(/* hash of deepExtend functions */);
return _;
}
}
}
...
However, I am stuck at what to do at this point since underscore.mixin.deepExtend does not return a hash of functions that _.mixin() requires.
Is there a way to load backbone-deep-model with RequireJS without modifying source code?

This may not be the answer you're looking for, but one option that I'd personally advise is to just leave Underscore (and any mix-ins, and probably also Backbone and jQuery) out of Require entirely. The main advantage of this approach (beyond making your problem go away as a side effect) is that you don't have start every require module by importing the same library (or libraries if you do the same with Backbone/jQuery).
True, this slightly "pollutes" the global space, but in my opinion having an _ (or $ or Backbone) variable in the global namespace won't hurt anything. It will however solve your problem, avoid the need for a shim at all, and save you a lot of importing. And of course you can (and should) still use Require for your own code, as keeping your variables from "polluting" the global namespace will save you future headaches.
Just a thought.

You can shim backbone as a dependency:
shim: {
// this is an example, I don't know what are the actual dependencies are
'deep-model': ['backbone', 'underscore']
}
and them when you add it as a dependency it will operate on backbone:
define(['backbone', 'deep-model'], function(Backbone) {
// backbone now has deepModel in it
});

Related

Why requireJs wouldn't load defined dependency modules?

I am having problem while using Require.js to load dependencies for my module. Basically I have following module in which I define extension of Backbone Model.
define(["models/services/ProjectServices"],
function (ProjectServices) {
var SomeModel = Backbone.Model.extend({
sample: function () {
var servicesFromDependency = ProjectServices; //undefined
var projectServices = window.require.s.contexts._.defined["models/services/ProjectServices"]; //defined and Ok
}
});
return SomeModel;
}
);
In this module I want to use already defined ProjectServices module. In order to do that I add it as a dependency. The thing is that within defined sample function ProjectServices is showing as undefined. But if I look directly into require defined modules it is showing there correctly and I can use it (although I do not want as I don't like to hack it this way). To add more context, I am also using this ProjectServices dependency on other module and there it is loaded properly through define function.
Any suggestions on why module would not be loaded?
Try this inside a module:
var ProjectServices = require('models/services/ProjectServices');
I think in many situations, there is no need for window global assignment and I try to avoid while using requirjs.
The only thing I can come up with is a possible circular reference, meaning that two modules require each other (which should not be the case).
As you say that the require works well in other modules, it should not be due to a missing return statement in the required module, or a wrong path. (You might check this anyway).

Place of the helper functions in Backbone

I've got some functions like this:
function killOrphans(str) {
return str.replace(/\s([\dwuioaz]{1})\s/gi, ' $1\u00a0');
}
which is generally a helper function to remove single letter words (orphans) from the end of a line (Polish typography demands to do this).
Question: how do you treat a library of such functions? A module in the global scope? extending jQuery? Extending the prototypes of String, Array etc.? (I don't think it's a good idea...). I think I'll go in the direction of underscore and create a module, but I'd be glad to hear real life examples of your way to do it.
Adam
In my project, I've used a variety of strategies for helper functions.
Extra methods on a view or a model.
var MyView = Backbone.View.extend({
initialize: function(){...},
render: function(){...},
helper: function(){...}
});
Use a helper module.
var myHelpers = {
foo: function(){...},
bar: function(){...},
baz: function(){...}
};
Extend an existing lib.
jQuery.fn.foo = function(){...};
Use an IIFE (best for functions you'd like to keep private)
var MyView = Backbone.View.extend({
initialize: function(){...},
render: function(){...},
myMethod: (function(){
function helper(){...}
return function(){
// do stuff here, using helper()
}
})()
});
Also, if you're not working in node.js which automatically provides a module system, it's worth using some strategy, such as browserify or requirejs, to export and import modules in a sane way, rather than having everything hang off the global namespace.
It is a question for Nobelprize - how to structure Javascript code with such a dynamic language. There are a lot of patterns and library solutions for this problem. For example:
You can extend prototype but then you are creating coupling. You can
create a module, but do you need module for one function ? You can
use Requirejs, annonymous functions...
Best real life examples are in production code. Take a look how jQuery deals with structure. And also Backbone. Try to learn classic design patterns - they are source of gold for any JS developer.
My advice is to dig deeper into JS and discover why language is designed in such a way. My first language was Javascript but I didn't make any progress until I started to learn something more traditional like in OO sense.

Dealing with require.js

I guess I do not completely understand the way require.js works. Here is a a simple module I've created:
requirejs.config({
paths: {
'underscore' : 'libs/underscore-min',
'backbone' : 'libs/backbone-min'
}
});
define([
"underscore",
"backbone"
], function(_, Backbone) {
console.log(_);
console.log(Backbone);
var MyCollection = Backbone.Collection.extend({
initialize: function() {
this.on("all", function(event) {
console.log(event);
});
}
});
return MyCollection;
});
I load it from my html:
<script data-main="js/mycollection.js" src="js/libs/require.min.js"></script>
The problem is it works intermittently. Sometimes Backbone object is there in the function when I need it, sometimes it doesn't (and gives me http://requirejs.org/docs/errors.html#notloaded error). If I just hit reload in the browser, I'd get 50/50 change of it working.
I must be missing something really basic here, the reported error doesn't make any sense to me, I thought the whole idea of the require.js mechanism is that my function will be called only when all the dependencies are loaded.
Since Underscore and Backbone haven't been defined as AMD modules, require.js does not know that Underscore is a dependency of Backbone. So I guess what happens in 50% of your cases is that Underscore isn't loaded when Backbone tries to use it.
You can use the require.js shim config http://requirejs.org/docs/api.html#config-shim to tell require.js about the dependency structure.
My guess is that you're not using an AMD version of underscore and Backbone. If that's the case and the two packages aren't wrapped as AMD modules - then the define function which is meant for modules won't work like it should.
For non-module js scripts, the more appropriate form would be to use the require() function.
OR - you can find the AMD version of underscore and Backbone here. AMD support was taken out of Underscore and Backbone at some point.
AMD Underscore
AMD Backbone

backbone with requirejs : View and subviews and r.js

I have a view that requires requires Backbone, Undescore, jquery etc.
example
define(['jquery','undescore','backbone','subviewA', 'subviewB'], function($,_,Backbone, SubviewA, SubviewB){
var View = Backbone.View.extend({
//other methods here
render : function() {
this.subviewA = new SubviewA();
this.subviewA.render();
this.subviewB = new SubviewB();
this.subviewB.render();
return this;
}
});
});
subview example
define(['jquery','undescore','backbone','text!templates/subviewA'], function($,_,Backbone, template){
var SubviewA = Backbone.View.extend({
//other methods here
render : function() {
this.$el.html(template);
return this;
}
});
});
My question is if I need to include jquery, undescore and backbone in the subviews too ir I can omit them?
EDIT
I am asking cause in r.js I need every time to tell it to not to biuld those dependencies inside each module.
Theoretically, if you don't use the $ or _ symbols in your views, you don't need to list jquery and underscore as direct dependencies of your module (whether it is a view or a subview doesn't change that).
You do need to include backbone though, since you reference it directly with : Backbone.View. If you want to be absolutely sure that the Backbone symbol is defined you should declare it as a dependency.
Some libs register themselves both as AMD modules and as global variables (typically jquery does that). Backbone doesn't support AMD directly and registers itself at the global level regardless of how it is used. In theory you could not declare it as a dependency, but then you have the risk that require will try and load the script before backbone is loaded in which case the Backbone symbol will not be defined.
It doesn't matter much if you redondantly declare the dependencies except for the additional caracters, thus the additional script size.
You can omit any requirements which aren't used.
In your examples (ignoring omitted code!), you can remove jquery and undescore (sic) but not backbone (since you use it via Backbone.View.extend).
Obviously you need to keep your requirement names and variables in sync.

How do I use namespaces in Backbone with RequireJs

I am unsure how I use namespaces in an modularized (RequireJs) Backbone environment.
I have thought a bit how it could look like but am totally unsure if this is the right way.
app.js (getting executed by main.js)
define('App', ['underscore', 'backbone', 'Router'], function( _, Backbone, Router){
function initialize(){
var app = {}; // app is the global namespace variable, every module exists in app
app.router = new Router(); // router gets registered
Backbone.history.start();
}
return { initialize: initialize }
});
messages.js
define('MessageModel', ['underscore', 'backbone', 'App'], function(_, Backbone, App){
App.Message.Model; // registering the Message namespace with the Model class
App.Message.Model = Backbone.Model.extend({
// the backbone stuff
});
return App;
});
Is this the right approach or am I fully on the wrong way (if yes please correct me!)
Have a look at the TODO Backbone + requireJs example:
https://github.com/addyosmani/todomvc
Found an real example app using namespaces like mentioned in the start post: https://github.com/nrabinowitz/gapvis
Just have to test it the next days
I'm new to backbone, but just read a snippet from the requirejs docs.
A module is different from a traditional script file in that it defines a well-scoped object that avoids polluting the global namespace. It can explicitly list its dependencies and get a handle on those dependencies without needing to refer to global objects, but instead receive the dependencies as arguments to the function that defines the module. Modules in RequireJS are an extension of the Module Pattern, with the benefit of not needing globals to refer to other modules.
To me, this sounds as if when using requirejs, you can forget all about namespaces, as requirejs takes care of it. You would just have access it differently. When you want to access it from another module, you'd put a path to the file in your array of dependencies, and and feed a respective variable to the following function.
define(["folder/a-script", "folder/another-script"], function(AScript, AnotherScript) {
// In here the scripts are loaded and can be used, but are called by
// their relative name in the anonymous function.
}
);
Anyway, perhaps in some cases there is still a need to namespace something, but I think in general, it's worth reading the docs to see if you need to.

Resources