English |  Español |  Français |  Italiano |  Português |  Русский |  Shqip

Developing a Backbone.js Edge

Chapter 9: Modules, Build Tools, and Preparing for Production

The code in the Hubbub project was organized in a very simple way using vanilla JavaScript without any special tools. This was done so that it was easy to get started with the project and understand how everything works. As you work on a real-world project, there are a variety of tools out there to help setup your project, organize your code, and build your project to be optimized for production. We'll walk you through a few of the important things to remember and some useful tools to help make it all manageable. Before we do that, though, let's look at fetching asynchronously and how to use Backbone.LayoutManager.

Fetching asynchronously

Up to now, all examples have been synchronous operations. This means we have not had to work around any I/O from network/file loading, timers, or anything else that may cause asynchronous behavior.

This is desirable when working without an HTTP server serving your markup. Since browsers forbid asynchronous requests unless your application is served from a web server, it's less than ideal to teach this method in examples.

The benefits of loading asynchronously through a method like AJAX is that you are able to break down templates into separate files with respective syntax highlighting, and thus you can easily pre-compile with existing build tools.

An example of this fetching implementation could look something like:

var MyView = Backbone.View.extend({
// Assign the file path to fetch the template contents from.
template: "templates/my-template.html",
// Since this method is now asynchronous, pass a callback to know
// when it's done.
fetchTemplate: function(done) {
// Use jQuery to asynchronously fetch the template.
$.get(this.template, function(contents) {
// Compile and send the template to the callback function.
done(_.template(contents));
}, "text");
}
});
// Create an instance to test fetch on.
var myView = new MyView();
// To access the template function now you would need to pass a
// callback to fetchTemplate.
myView.fetchTemplate(function(template) {
// Render the template.
template({ some: "data" });
});

This should be enough to help get you started with the idea of fetching asynchronously with Backbone.

Backbone.LayoutManager

We didn't cover this in Chapter 4: View, but let's take a quick look at an example of how a plugin View could look different from a typical Backbone.View:

var MyView = Backbone.Layout.extend({ 
template: "#someTemplate",
// Tell the View what data to provide to your template.
serialize: function() {
return {
model: this.model };
},
// Automatically have render defined for you, so just bind it to any event
// that should affect the View.
initialize: function() {
this.listenTo(this.model, "change", this.render); },
// Declaratively assign nested Views.
views: {
// Each line is a selector that exists within #someTemplate and a
// View instance that will be rendered and inserted into the element
// found by the selector.
"header": new HeaderView(),
"section": new ContentView(),
"footer": new FooterView() },
// Can attach jQuery plugins after rendering is complete.
afterRender: function() {
this.$el.someJqueryPlugin(); }
});

This is just enough to get your feet wet, but we felt it was important to show you a plugin View in Backbone. Now let's take a look at what is required with using Backbone on a production server.

Different Goals in Development vs. Production

While of course you want your application to generally behave the same way on your production server as it did from your local development server, there are some pretty significant differences in goals to keep in mind. Let's look at the main differences and discuss how modules and build tools can add harmony to an otherwise conflicting situation.

Development Mode

While you're writing code for your application, things should be setup in such a way that makes you, as a developer, the most efficient are:

  • Code should be logically separated into smaller files that are more managable than one giant file with everything in it. This will help you find the code you need, allow you to focus on one part at a time, and it will also make it easier for other teammates to work on the project at the same time.
  • There should be as little delay as possible between writing code and being able to test it (both running unit tests, and running your application in a browser).
  • Make your code as readable (understandable) as possible by including plenty of whitespace and comments.
  • Keep all required assets on your local development machine so that you can work on your application even without an Internet connection. This means not relying on a public CDN for jQuery, for example.

Production

When code is running on your production server; however, things should be setup in such a way that provides the best experience for end users, which means doing whatever you can to improve performance. Some examples are:

  • Files should be as small as possible (so they are downloaded faster). To remove every byte possible from your application, there should be no whitespace or comments. This is called minification.
  • There should be as few downloads as possible, because there is overhead for each additional HTTP request, and because browsers have limits on the number of parallel connections it will make per hostname. Combining multiple source files into one file is called concatenation.
  • Your code should be set to be cached by browsers (when it hasn't changed), so that a user's browser won't have to redownload the assets every time they visit your web application.
  • Use a Content Delivery Network (CDN) for your static assets (JavaScript, CSS) so they can be downloaded as quickly as possible.
  • For the most commonly used libraries like jQuery, consider using a globally shared CDN (e.g., Google's Hosted Libraries) so that even your first-time visitors won't have to download a new copy of jQuery, most likely.

Now let's discuss a few tools to make all of this easier.

RequireJS

RequireJS is an excellent way to split your code into AMD modules (separate files), define dependencies between them, and then load your multiple JavaScript modules/files asynchronously without anything breaking.

In our Hubbub example, in index.html, you'll see we have a bunch of <script> tags. Browsers are forced to download and execute these files sequentially, which can be bad for performance. Using RequireJS (or another script loading tool) can allow multiple JavaScript files to be downloaded in parallel and then run in the correct order based on the defined dependencies needed for each module.

In the example below, we'll define two AMD modules and show how one can show a dependency on the other.

In models/issue.js:

define(['backbone'],
function(Backbone) {
var Issue = Backbone.Model.extend({
defaults: { name: 'Untitled' }
// remainder of Issue Model definition here...
});
}
return Issue;
});

In views/issue.js:

define(['backbone', 'models/issue'],
function(Backbone, Issue) {
var IssueView = Backbone.View.extend({
render: function() {
this.$el.html('Name:' + this.model.get('name'));
return this;
}
// remainder of Issue View definition here...
});
}
return IssueView;
});

Optimizing RequireJS projects with r.js

Above we said that in development we wanted separate files for each logical section of code. RequireJS helps make this possible. But we also said that in production there should be as few files as possible. There's a tool, r.js, to help with this! If you've got Node installed on your computer, you can run this command before deploying your code to production:

$ node r.js -o baseUrl=. name=main out=main-built.js

If you want to learn more about RequireJS, r.js, and build optimizations, see RequireJS's Optimization page.

Grunt

Grunt is a task-based command line build tool for JavaScript projects, that will help make easy  many of the best practices described above.

Here's an example "gruntfile" to configure grunt with a Backbone project. With grunt installed and configured, you could simply run: 

$ grunt release

and Grunt will, based on the gruntfile linked above:

  • lint your code, checking for common programming mistakes and enforcing best practices
  • precompile JavaScript templates used by Backbone Views.
  • concatenate each RequireJS/AMD module (using r.js) into one file
  • minify that file, making it as small as possible by removing whitespace and comments, shortening variable names, etc.

By integrating a tool like grunt and having a "build" process, you can get the best of both worlds (easy to work with development environment, fast application in production). If you use grunt, be sure to check out grunt-contrib and all the plugins listed on gruntjs.com.

Backbone-Boilerplate to get started with Backbone, RequireJS, and Grunt

If you want to get started with using Backbone with RequireJS, we highly recommend checking out Backbone-Boilerplate. It nicely lays out:

  • How your files and directories can be laid out
  • Examples of RequireJS with Backbone.js classes
  • An example RequireJS config file
  • An example Grunt file already configured
  • How to asynchronously fetch and compile templates for development

Brunch.io

An alternative to Grunt is Brunch, an "application assembler" that comes with many Backbone based "skeletons". Like Grunt, it automates linting, concatenating, precompiling and minifying. It is a flexible build tool and works with RequireJS or a simpler CommonJS module syntax. It's configuration files are less verbose than Grunt's, and it's easy to get started with. One of the advantages of using BackboneJS in your project is that there is a large community and many excellent tools to choose from. 

Yeoman

Yeoman is a Google project that incorporates Grunt, but adds the following additional functionality:

  • Package management via bower
  • Built-in headless testing with PhantomJS
  • Advanced scaffolding and generators 

Other Build Tools

If you prefer standalone tools over Grunt, some other great tools include UglifyJS, Closure Compiler, YUI Compressor, and the Asset Pipeline in Ruby on Rails.

Conclusion

All of the different tools out there can be overwhelming when beginning your Backbone development adventures (especially when you're already trying to learn a new language or framework), so don't feel like you have to use them all at once. Sometimes it's best to work on a small project and structure to get things done quickly and simply (like our Hubbub app). Once you're comfortable with Backbone, you'll see the value some of these tools can provide. And if you sweat the details of performance, it can make a big difference in your user's happiness!

There has been error in communication with Booktype server. Not sure right now where is the problem.

You should refresh this page.