O'Reilly logo

Full Stack Web Development with Backbone.js by Patrick Mulder

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 1. The Bigger Picture

The goal of the first chapter is to provide some feeling of the environment of Backbone.js applications. This chapter is mainly about packages of JavaScript, how to fetch these from the command line, and how to bundle many JavaScript files into one single file.

To learn about the ideas behind Backbone.js, you want to manage as few abstractions as possible. This is why Node and the command-line is your main working environment for the first chapters. Later in this book, you will meet Yeoman, RequireJS and Grunt, resulting in workflow automation for JavaScript projects.

If you prefer to skip the command-line ideas now, and you want to get started with the browser and UX topics directly, you might want to read Chapter 2 first. But you want come back later to this chapter, to learn more on JavaScript modules and bundling JavaScript for the browser.

Summarizing, the goal in this chapter is to enter development with JavaScript modules, and we touch:

  • Getting Backbone.js via npm, via a CDN or from the project site
  • Basic bundling of JavaScript applications with Browserify and Stitch
  • A feeling on use cases for the CommonJS module format

Before you get started

Before you can build Backbone.js applications, it is very important that you know some basic abstractions to work with multiple JavaScript files at once.

There are two reasons:

  • You will need to fetch a number of JavaScript dependencies to get going with Backbone.js web applications
  • The view and data layer in Backbone.js applications are generally broken up into separate JavaScript modules

Bundling JavaScript for the browser is an important topic with many options. A related question is: How to organize your JavaScript dependencies, and share your projects with others? To follow the answers of this book, you require a working Node.js setup.

If you don’t yet feel comfortable with JavaScript or haven’t setup Node.js, you might want to look at the JavaScript refresher in the book references. In Appendix A, you will find some instructions to setup NodeJS.

Backbonify your Stack

Like Lego, the philosophy of Backbone.js is centered about combining small building blocks that do one thing well. As introduction, you’ll see some of the simplest ways to work with Backbone.js in this chapter.

Besides Backbone.js, you need to fetch two additional libraries to get started. Underscore.js is a fixed dependency for Backbone.js, and will help you with filtering and sorting data, as well as working with arrays and functions.

Second, you need a library for manipulating the document-object-model, or DOM. One of the most popular libraries for DOM manipulation is jQuery, but there is also Zepto.js for mobile use cases.

So, how can we import these libraries into the web application? There are several ways:

  • Fetching local copies by using a package manager, here npm
  • Working with remote references, or CDN networks
  • Fetching local copies by downloading the libraries manually

Using npm

If you want to use NodeJS, and we will be using it a lot in this book, you can fetch Backbone.js with Node’s package manager, or npm.

npm is one of the most important command-line tools in Node. With npm and the site npmjs.org, you can quickly access more than 60 thousand JavaScript modules. Although npm has its roots on the server-side, you can use it for developing browser web applications too, as we will see later in this chapter.

First, if you start work on a new project, it makes sense to initialize the project directory with npm init:

$ npm init

You’ll get asked a number of questions about your project. You can leave most parts empty for new projects, if you are unsure of the answers at the start. The important point is that you obtain a file package.json, similar to:

{
  "name": "sandbox",
  "version": "0.0.0",
  "description": "",
  "main": "index.js",
  "author": "Patrick",
  "dependencies": {
  }
}

Next, we fetch Backbone and its dependencies. You can fetch Backbone with npm as follows:

$ npm install backbone --save
npm http GET https://registry.npmjs.org/backbone
npm http 304 https://registry.npmjs.org/backbone
npm http GET https://registry.npmjs.org/underscore
npm http 304 https://registry.npmjs.org/underscore
backbone@1.1.2 node_modules/backbone
└── underscore@1.6.0

We use the --save argument, to save Backbone as a fixed depenency for the project. It is also possible to save a dependency only for development with --save-dev.

After you ran the command, you should have a node_modules directory that contains Backbone and its dependency Underscore.js. We also need jQuery for DOM manipulation, and we add this library with:

$ npm install jquery --save
npm http GET https://registry.npmjs.org/jquery
npm http 304 https://registry.npmjs.org/jquery
jquery@2.1.0 node_modules/jquery

We now have the libraries as Node modules that support the so called CommonJS format. What this is, and how we package these modules for the browser, will be discussed in the next sections.

For now, take away that npm can create a project manifest and can manage your JavaScript dependencies from the command line. Once Backbone.js is a dependency there, it will allow others to run npm install on your project, and easily get a working environment.

Note

There are a number of solutions to manage JavaScript dependencies. For example, we will meet Bower in Chapter 10, when we look at automated workflows for frontend web development with Grunt.

Local Backbone.js

If you are rather new to JavaScript and NodeJS, you may want to experiment first with Backbone.js without using Node. In this case, you can visit the site http://backbonejs.org first.

There, you can fetch a copy of Backbone.js and store it as a local copy on your machine. Local copies might also be handy, if you work with server-side web frameworks, such as Ruby-on-Rails, that have their own JavaScript build process. Last, fetching a local copy might be interesting when you want to play with the newest version of Backbone.js.

To download Backbone.js from the project site, you can scroll down until you see the project download area as show in figure Figure 1-1. In most cases, you want to download the development version. Then, you must download the Backbone.js dependencies jQuery and Underscore.js, which you can respectively fetch from http://underscorejs.org/ and http://jquery.com/download/.

A simple approach to download Backbone.js is to visit the project page of Backbone.js
Figure 1-1. A simple approach to download Backbone.js is to visit the project page of Backbone.js

Visiting the homepage of the Backbone.js project once in a while is a good idea to be informed about changes in the project too. If you want to get a feeling what is going on in the project, you should also visit the project repository at Github. By looking at the latest commits in Github or the discussions at the Github issues, you can learn many things on JavaScript and open-source development. So, you might want to keep track of that too.

Backbone.js via Content-Delivery Networks

When you want to share examples online, a good option to load Backbone.js is to fetch the libraries from a content-delivery network or CDN.

Note

Loading Backbone.js and its dependencies from a CDN is necessary when working with services such as JSFiddle, JSBin or Codepen.io. These online sandboxes can help you with sharing problems or publishing work.

There are a number of CDNs that host a version of Backbone.js, but a very good CDN network is provided by Cloudflare, see: http://cdnjs.com/. If you want to use Backbone.js with a CDN, you can use the following script tags:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.0/backbone-min.js">
</script>

To test this, we create a simple HTML file:

<html>
 <head>
   <!--- insert CDN scripts here -->
 <script>
   $(document).ready(function() {
     console.log(Backbone);
   });
 </script>
 </head>
<body>
</body>
</html>

Let’s check this page in the browser. If all goes well, we should see a Backbone object printed in the console of the browser, similar to Figure 1-2. However, you might experience problems without network access or wifi. We will see in a moment how to fetch local copies of the libraries to work in offline mode too.

The <script> tags in the index.html fetch Backbone.js and its dependencies from a CDN. When the browser triggers the document’s “ready” event, we should see the Backbone.js is ready for business.
Figure 1-2. The <script> tags in the index.html fetch Backbone.js and its dependencies from a CDN. When the browser triggers the document’s “ready” event, we should see the Backbone.js is ready for business.

Modules, Packages and Servers

By now, you tackled the first hurdle for building web applications with Backbone.js. You can manage some JavaScript dependencies with npm or you can manually download a version of Backbone.js.

Next, how do we bundle multiple JavaScript files such that you only have to worry about a single JavaScript file in the browser? Imagine working with 10-20 JavaScript files, setting each <script> tag manually in the HTML would be tedious. In this book, we look first at approaches to bundle CommonJS modules, and in later chapters at working with RequireJS.

To understand where we are heading, and why there are a number of approaches to bundling assets, let’s have a look at the distributed application design in Figure 1-3.

For web application development with Backbone.js, we want to manage both: Frontend assets as well as data coming from an API. Backbone.js is just one layer in a larger application stack, and influences how we setup environments for development and production.
Figure 1-3. For web application development with Backbone.js, we want to manage both: Frontend assets as well as data coming from an API. Backbone.js is just one layer in a larger application stack, and influences how we setup environments for development and production.

Your application stack might change, depending on the requirements that evolve from users. If your primary goal is to deliver a mobile web application, we might want to tune every line of JavaScript that we send to the client. An example stack for mobile web applications is given by Walmart’s mobile shopping cart, and we will discuss this stack based on RequireJS and Thorax in later chapters.

If it is important that search engines can crawl your application, rendering of templates should be done on the server to provide links for search-engine optimization and a fast first page load. Backbone.js integrates well with so-called “isomorphic” JavaScript applications, where parts of an application can run on both the client and server. Airbnb’s Rendr.js library shows how client- and server-side rendering can be combined for this use case with Browserify and CommonJS modules.

In other cases, a Backbone.js application is just part of a larger server-side web application. Some server-side approaches, such as Browserify and Express with Stitch, support bundling JavaScript files with the CommonJS module format. Other server-side approaches support RequireJS based workflows and JavaScript modules in the so-called AMD format.

Don’t worry too much about what is best for you now. The important point here is to experiment with the idea of “modular” JavaScript, and observe the influence this has on your use cases and application stack.

CommonJS Modules

When JavaScript was first specified, <script> tags were the main constructs to run JavaScript. When NodeJS arose, there was a new need to re-use JavaScript dependencies as modules across projects. The NodeJS community proposed the CommonJS module format. But, should you “require” Backbone as a CommonJS module in the browser too? Yes, it depends …

There are a number of different opinions what the best module format is. Besides the CommonJS module format, there is the RequireJS format. RequireJS has been developped specifally for the browser environment. Yet, as with many questions in software development, the right tool depends on your job.

As the CommonJS format is the default server-side approach, you can have an option to run the same code on the server that runs in the browser, or vice-versa. This can be interesting for certain kinds of applications, since we can share the same logic to render views or validate models on the server as in the browser. The Rendr library from Airbnb for example follows this approach.

Also, since npm uses the CommonJS format by default, it can be nice to build quick prototypes, and to experiment for learning purposes as we are doing here. We will discuss RequireJS in the second half of this book, when we are looking at static web pages, without backend integration.

The general syntax to “require” Backbone as a CommonJS module looks as follows:

var Backbone = require('backbone');

How does this require work? In a Node environment, the JavaScript runtime would search the local node_modules paths for the Backbone module. If it can’t find the module there, Node would search the global node_modules folder. At the browser, we don’t have these paths, and a browser does not natively know about CommonJS modules. To fix this, we need to wrap JavaScript modules with tools such as Browserify and Stitch to resolve dependencies. We will discuss this is a moment.

First, let’s look closer at the syntax to define a CommonJS module. Say, you want to wrap a function to print “Hello World” in CommonJS. For doing this, we “export” some JavaScript code, that we later can “require”.

So, we could define a module in a file greeting.js:

module.exports = function() {
  console.log("Hello World!");
};

In the Node console, you can now require this module with:

> var greeting = require('greeting');
> greeting();
Hello World!

The same module can be executed in the browser. But first, we need to package it as a module for the browser.

Beyond index.html

Now that you learned some basics about JavaScript modules, let’s look at ways to “require” these modules in the browser. In a browser, all we have is HTML and <script> tags [1].

Loading an index.html in the browser with references to a Backbone.js app with <script> tags only works for small projects. Putting too much JavaScript in HTML can easily evolve into hard to maintain code. The index.html file is a good entry point when spiking out ideas, but it is good to have JavaScript code in separate files from the start.

To setup a JavaScript project, we first create some directories. One directory to put the JavaScript files of the application. And, you need one directory for with bundled JavaScript assets that are delivered to the browser.

Let’s setup these directories. First, we setup a directory for the JavaScript sources:

$ mkdir app

Then, we setup a directory for the bundles files. You can later reference this directory from the index.html:

$ mkdir static

Last, we need some simple HTML. This file can be placed in the project root:

<!DOCTYPE html>
<html lang="en">
<head>
      <meta charset="utf-8">
      <title>PAGE TITLE</title>
    <!-- scripts -->
</head>
<body>
</body>
</html>

Now, back to the main question of this section: where and what <script> tags should you use in order to load Backbone.js and the web application? In the previous section, we learnt already the basics of CommonJS modules. And, as often with JavaScript, you have different options to prepare CommonJS for the browser.

Browserify

As mentioned above, npm gives us access to the repository of Node modules. Also, the CommonJS module syntax is rather simple, and allows us to maintain a simple boilerplate for a JavaScript project. However, how can we run CommonJS modules in the browser? The missing piece in the puzzle is: Browserify.

Browserify ( https://github.com/substack/node-browserify ) walks through the dependencies of an application, and assembles multiple files into one. In section Using npm, you used npm already to install Backbone and its dependencies. In addition to app and static, you should have a directory node_modules at this point, and your project directory tree should look like:

|-app
|-node_modules
|---backbone
|-----node_modules
|-------underscore
|---jquery
|-static

To bundle the JavaScript for the browser, let’s first make a module that loads the Backbone module. In app/main.js, we insert:

var Backbone = require('backbone');
module.exports = function() { return Backbone };

That this is a valid module, can be tested with Node. If you enter the console with node, you can now import the module with:

$ node
> require("./app/main")
[Function]
> require("./app/main")()
{ VERSION: '1.1.2', ... ]

This is fine, you might think, but what has this result from the Node console to do with a web browser? For some use cases, being able to run JavaScript on both the server and the browser VM, allows you to better re-use ideas for rendering or validating data for example. This is less obvious from this small example, but it matters big deal when you want to build an online shop or social network, that needs both fast processing times on a server, as well as, responsive interfaces on the client.

Also, since Node and Node modules are supported from the command-line, we can quickly spike out new ideas. Now, how can we see the same result from the Node console in the webbrowser? The magic comes from Browserify. We can use the following browserify command to bundle a module and its dependencies:

$ browserify -r ./app/main:app > static/bundle.js

What does this command do? A number of things:

  • Browserify supports different modes to bundle JavaScript. To bundle the file app/main.js as module, you can use the -r directive.
  • To map the local module ./app/main.js to a better module target name, you can use the colon. See browserify --help for more options.
  • Since browserify just provides a plain text file output, you can use a > to save the command’s output into a file static/bundle.js .

Then, if you look in the resulting file static/bundle.js, you’ll see that the output of Browserify resulted in two things.

First, Browserify output starts with a wrapper function, that implicitly defines what and how to “require” code from this file:

require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"
&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"
+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return
s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&
require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var Backbone = require('backbone');
module.exports = function() { return Backbone };

Second, Browserify bundled up all JavaScript dependencies in this file, such as jQuery, Underscore and Backbone. Generally, you don’t want to work in this large output file, but you want to use the original JavaScript files. The Browserify command can then be repeated as often as you like to create new static files.

Note

To prevent you from typing browserify every time a file changes, there is a supporting tool watchify that automates builds as soon as an input file changes. To keep to code examples consisten, the book examples only show the browserify command. Have a look at https://github.com/substack/watchify for more information on the watchmode.

To run the bundled code in the browser, let’s add a line to load the file static/bundle.js from our index.html above. In index.html, we add:

<script src="static/bundle.js"></script>

If you now load the index.html from the browser, you can run require("app")() in the browser console, and you should see some output similar to figure Figure 1-4.

With Browserify, we can package CommonJS modules and run these in the browser.
Figure 1-4. With Browserify, we can package CommonJS modules and run these in the browser.

Note

If you want to learn more on combining client- and server-side rendering, e.g. in the context of an ecommerce project, you can look at the Rendr library from Airbnb or read up on so-called “isomorphic” JavaScript web applications.

A slightly more difficult use case is, to require modules as local application dependencies, such as custom Backbone views or Backbone collections from a directory ./app/views or ./app/collections. Don’t worry about what views and collections are right now, we will discuss these in the next chapter.

The important point right now is an approach to require local modules from an application directory. First, you create directories for views and collections:

$ mkdir app/views
$ mkdir app/collections

Browserify follows the Node convention for looking up modules in directories. So, you need to create a directory node_modules inside the app directory, to follow the convention.

$ mkdir app/node_modules
$ cd app/node_modules
$ ln -sf ../views
$ ln -sf ../collections

Based on symbolic links to the ./app/node_modules path, Browserify can find your local modules and you can easily require a module in your application like this:

require('views/movie');

With this setup, you can leave out any relative paths for your require() statements.

Combining Express.js and Stitch

Browserify is not the only way to run CommonJS modules in the browser. While Browserify is a nice tool to bundle modules from the command-line, some developers prefer to maintain a project manifest that explicitly lists a project’s dependencies. How manifest files look like, depend on your application stack, but the general goal, as with Browserify, is to bundle many files into one file.

For some application stacks, e.g. when you work with a web server similar to Express.js, CommonJS modules, or CommonJS like require of modules, can be done with some simple configurations. For web servers based on NodeJS, there are the package managers Stitch and Mincer, which are somewhat similar to the Sprockets asset manager for web servers in Ruby.

Note

If you come from Ruby-on-Rails, you probably have used Sprockets, the asset pipeline in Ruby-on-Rails. Sprockets is very similar to Stitch, but supports its own require syntax. If you like that syntax, you might want to check out Mincer, a port of Sprockets to Node.js: https://github.com/clarkdave/connect-mincer

To illustrate some ideas behind using a package manager and a manifest file, let’s walk through an example with Express.js and Stitch. The role of the web server is to deliver HTML, CSS and JavaScript to the client. Stitch helps us to package the frontend JavaScript project.

An Express.js server is very simple to setup. Similarly as you did earlier, you can use npm to fetch the Express.js module:

$ npm install express

Express.js provides a nice language to manage HTTP requests and responses on the server. Let’s create a directory for a server next:

$ mkdir server

To get a basic server going, you can create a file server/app.js that serves a simple index.html page first. For this, we insert the following code in server/app.js:

// First, we require Express.js as dependency
var express = require('express');
var logger = require('morgan');
// a helper to resolve relative paths
var path = require('path');
// Then, we initialize the application...
var app = express();
app.use(logger({ immediate: true, format: 'dev' }));
// We add a basic route that serves an index.html
// ... let's use the same as above
app.get('/', function(req, res) {
    var html = path.resolve(__dirname + '/../index.html');
    res.sendfile(html);
});
// Let's listen on port 5000
app.listen(5000);
console.log("Server is running.");

And, if we insert the HTML from above, we can start the server with:

$ node server/app.js

We can check that our new server speaks HTTP from the command line with Curl:

$ curl 0.0.0.0:5000

And this should return the HTML from previously, as we can check in a browser too.

So far, the server-side Express.js application just transports HTML. Let’s look next at how to wrap JavaScript “modules” with Stitch.

Similarly as we did for Express.js, we can install Stitch with:

$ npm install stitch

Sitch assembles multiples files into one file via configurations of paths. In the previous file server/app.js we now add:

var express = require('express'),
    path = require('path'),
    stitch  = require('stitch');
// To "stitch" the client-side modules together
// we create a package
var package = stitch.createPackage({
  paths: [__dirname + '/../app'],
  dependencies: [
    __dirname + '/../libs/jquery.js',
    __dirname + '/../libs/underscore.js',
    __dirname + '/../libs/backbone.js',
  ]
});
var app = express();
app.use(express.static(__dirname + '/public'));
// Whenever a request goes to the client, we deliver the modules as client.js
app.get('/static/bundle.js', package.createServer());
app.get('/', function(req, res) {
    console.log("--> /");
    var html = path.resolve(__dirname + '/../index.html');
    res.sendfile(html);
});
app.listen(5000);
console.log("Server is running.");

With this setup, Stitch manages and serves the client-side application whenever we request /client.js . Stitch resolves the modules in the dependency tree of the client-side application. Let’s check this.

First, we create a directory for the client-side application:

$ mkdir app

And a file app/init.js where we insert:

console.log("hello world");

Now, we can look at what Stitch does with:

$ curl 0.0.0.0:5000/static/bundle.js

Inspecting the file, we see some code that was added by Stitch, and at the bottom some code from our init.js file:

//....
{"main": function(exports, require, module) {console.log("hello world"); }

We now can use the file main.js as a CommonJS module, e.g. with require("main") in the browser console. We will see in the next sections, how to work with those to build the Backbone application.

Stitch has less power in resolving dependencies as Browserify has, but Stitch will do fine for most examples in this book. Instead of manually configuring and setup Underscore, Backbone and Stitch, you can also declare Backbone in the global scope or load Backbone from CDN networks.

When Things go Wrong

Working with a web browser for development can be unusual for backend developers. A browsers’ development console is a great playground however, as is Node’s read-eval-print-loop (REPL). Many problems with Backbone.js relate to not using the correct JavaScript syntax or idiom, and for many problems typing some code into the REPL is a good start.

Problems with rendering and the DOM can often be debugged with breakpoints in the browser. With breakpoints, you can understand why a variable has (not) the expected value, or why a rendering snippet is not reached. Debugging can also be done by putting traces of code with console.log(…) into your code. Be sure to remove these, when the code goes into production. Good advice on using the debugger in browsers can also be found at https://developer.mozilla.org/en/docs/Debugging_JavaScript.

On the server-side and on the command-line, you might find helpful to look at these tools:

  • jslint/jshint: These tools support you debugging the syntax of JavaScript. This is especially helpful to understand where you miss brackets, parentheses or a semicolon. Looking at the output of jslint, you can also improve your coding style. The rules that get applied in JSlint originate from Douglas Crockford book, “JavaScript: The Good Parts”.
  • console output: Often, it helps placing a line of console.log("-→ debug"); in your code, and see when some output is printed in the browser console. Sometimes code can return unexpectedly and never reaches the functions you expect.
  • JSON beautifiers: Working with JSON, you will often find it helpful to format some data with the jshon tool, or a similar browser plugin. By using the jshon beautifier, you can inspect data from the command-line with “curl” or “wget”, and compare the data values with what you expect.

Conclusions

You should have gotten a bit of a feeling for the development of a web application stack, about using npm and some Node modules to setup a basic Backbone.js application stack.

At this stage, you want to keep abstractions for an application stack at the bare minimum, such that the application is easy to read, and feels nice to play with. During the book, you will meet other options and trade-offs, that might be better for deploying an application and to your use case.

Since an application with Backbone.js lives part on the server and partly in the browser, you should have a feeling on the core application libraries, and how to setup some basic directories to organize your project files.

You should have played a bit with Browserify or with a JavaScript package manager that bundles multiple JavaScript files into one file. The widely popular RequireJS and JavaScript AMD module format will be discussed later in the book.

Right now, let’s stay in the web browser for the next chapters. You will learn about the basic abstractions that Backbone.js provides, and we will discuss Munich Cinema, the main example application of the book.



[1] There will be new ways to load JavaScript modules with the upcoming ECMAScript 6 specifiaction, but it will take some time before these are widely used

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required