How to start with Backbone.js: A simple skeleton app

Translations

TL;DR

It took me some time to get an optimal code/directory layout for Backbone.js apps.

Because I think this is a major pain for beginners, I prepared a well commented sample skeleton app.

Get it from Github while it’s hot, pull requests/feedback are welcome.

Prerequisites

You need a solid knowledge of JavaScript, familiarity with Backbone, Ruby, HAML, SASS and CoffeeScript to find this writeup useful.

Also, I’m developing on a Mac and have not tested this on other platforms. Although, I do not see any reason why it shouldn’t work.

1. Philosophy

Part of the success of Rails was the conventions and its predefined directory tree. While looking overwhelming and maybe annoying to a beginner at first, it soon becomes liberating. With experience things fall into place, and soon you feel feel like every tiny bit of code has it’s dedicated home.

Backbone, being the nimble, does not prescribe any particular code or directory structure. Until I read enough material and settled on this particular layout, I was feeling very confused and disoriented.

This skeleton app was extracted from a production app and then extensively annotated, to explain certain decisions and choices.

2. Backstory

When I first started to play with Backbone I was already heavily entrenched in the Ruby and Rails world. So naturally I thought, yeah, MVC, I know that. It turned out to be a bit farther from the truth than I wanted or cared to admit.

Disclaimer: I rarely developed pure client-side software, though I was using JavaScript extensively to make things faster and more responsive.

Thing is that MVC on the server-side is quite a bit different from MVC on the client. It has something to do with wiping the state clean each time you reload the page. Statelessness.

The client on the other hand is stateful and thus keeps all your bad practices in memory until they start to slow things down and eventually stop working.

This was the biggest client-side project for me so far, building out the Dubjoy editor for dubbing online video.

The hardest part of learning to develop MVC on the client and using Backbone was seeing the big picture. Seeing where all the little parts fit in and how this all works together in the grand scale.

So for the most part, my journey with Backbone consisted of finding out best practices for file and code organization, setting up the environment and directory structures.

Using backbone.js as a library was “easy”. (Not really, but this isn’t what this article’s about.)

One of the biggest mistakes I was making when starting out was trying to use Backbone constructs for everything.

Backbone is intentionally kept simple, because it’s supposed to be a complement to your own JavaScript. So just create your own App class, and populate it with the stuff and initialization your app really needs.

3. Tools

So a good workflow needs good tools. Here I’ll describe the tools that I found indispensable when developing in Backbone.

CoffeeScript, HAML and SASS

Because I resent cruft and redundancy, I’m a big fan of abstraction languages. Whenever I can, I opt for HAML, SASS and CoffeeScript.

The brevity they bring is paramount to me.

HAML Coffee

In Backbone, you usually need a template engine. Templates provide the markup for views. There’s a lot of solutions for this, but because I like to be consistent, the best choice was to use HAML.

Fortunately, there’s a library for this: haml-coffee, which enables you to use HAML intertwined with snippets of CoffeeScript.

Guard

To be able to use these languages seamlessly, you need some sort of a on-demand compiler. Turns out a Ruby gem called Guard does exactly this.

Guard is extremely flexible. It watches for file system changes and then doing something to files that changed.

Jammit

Jammit is an asset packaging library. It concatenates and compresses CSS and Javascript. It’s easy to use, but needs a configuration file, that defines which files to work on.

Sinatra with Isolate

Backbone apps are static files and you can run them directly off your hard drive. But to do proper paths and even maybe some API, we need a server.

Sinatra, a mini Ruby web framework, forms the base of the server. This enables some quick server-side magic as well as making an API for persistence.

To make this part as easy as possible to use, I packaged the server with Isolate, a small Ruby library for sand-boxing, which is like a mini-Bundler. When launching the server with rake server for the first time, it will check and auto-install it’s dependencies. It just works.

4. Using the skeleton

Getting started with a new app using my skeleton is trivial. It uses Ruby in several critical places, so be sure you have a working installation of Ruby, preferably of the 1.9 kind.

All of the files, directories and their meaning is described with more detail in the README file of the skeleton.

A working example of this app is available online. This way you can check if the console output is the same on your local setup and here.

Start by cloning my backbone-skeleton repo.

$ git clone https://github.com/mihar/backbone-skeleton.git my-new-backbone-app

Then use the bundle command that comes with Ruby Bundler to install the necessary dependencies for guard. Guard will compile our HAML, SASS and CoffeeScript to their native counterparts.

$ cd my-new-backbone-app
$ bundle

Once Bundler completes the installation, we can try starting Guard, to immediately start watching files for changes.

$ bundle exec guard

While leaving guard running, go to another terminal and let’s fire up a simple, bundled Ruby web server, that we’ll use for development. The server will install all of it’s dependencies by itself.

$ rake server

[1/1] Isolating sinatra (>= 0).
Fetching: rack-1.4.1.gem (100%)
Fetching: rack-protection-1.2.0.gem (100%)
Fetching: tilt-1.3.3.gem (100%)
Fetching: sinatra-1.3.3.gem (100%)
[2012-12-05 18:17:05] INFO  WEBrick 1.3.1
[2012-12-05 18:17:05] INFO  ruby 1.9.3 (2012-02-16) [x86_64-darwin11.3.0]
[2012-12-05 18:17:05] INFO  WEBrick::HTTPServer#start: pid=39675 port=9292

Now our server is listening on http://localhost:9292, so go ahead, and open that.

If you see “Skeleton closet”, everything is go.

Go check out the JavaScript console for more information.

5. Resources

The missing CDN

They host all the libraries, including Backbone and underscore.

Backbone Peepcode tutorials

Peepcode has been my friend since my Ruby and Rails days. They produce high-quality screencasts on a variety of topics.

They have a series of 3 videos on Backbone, going from the basics to some pretty advanced stuff.

Be prepared to shell out $12 per video, though.

Derick Bailey backbone posts

I’ve learned so much about the correct ways to do things on Derick’s blog. He’s a seasoned Backbone developer that has overcome many problems and written up on the progress. Wealth of resources.

Derick Bailey’s 4 part screencast

Haven’t seen this one yet, but if I’m judging by his blog, this should be very worth the money. 4 videos, $12 a pop.

Backbone Patterns

Documented patterns extracted from building many Backbone apps.

Organizing Backbone apps with modules

Article exploring similar problems of code/directory structure and organizations.

Backbone Boilerplate

A much bigger project with a similar goal as mine.

Backbone for absolute beginners

How to directly upload files to Amazon S3 from your client side web app

Why you need this?

You don’t want your heavy-weight data to travel 2 legs from Client to Server to S3, incurring the cost of IO and clogging the pipe 2 times.

Instead, you want to ask your server to give your client one-time permission to upload your data directly to S3. The process is still 2 legged, but heawy-weight data travels only on 1 leg.

On Amazon S3 this is implemented with CORS (Cross Origin Resource Sharing)

We use this at Dubjoy, where customers upload their huge video files to S3 for translation and voice-over, and we don’t want our Heroku server to have anything to do with heavy-weight video files.

Steps to implement this

  1. Set up Amazon S3 bucket CORS configuration
  2. Implement client-side JavaScript (CoffeScript, JavaScript)
  3. Implement server-side upload request signing (Ruby/Sinatra, trivial to do in any other language)

1. Amazon S3 bucket CORS configuration

Set this in AWS S3 management console. Right-click on the desired bucket and select Properties. Below, on the permissions tab, click Edit CORS configuration, paste the XML below and click Save.

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>PUT</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Content-Type</AllowedHeader>
        <AllowedHeader>x-amz-acl</AllowedHeader>
        <AllowedHeader>origin</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

2. Your web app

Head to GitHub repo with CoffeScript and JavaScript Class files to include. In your app, do the following:

HAML

%input#file{ :type => 'file', :name => 'files[]'}

or HTML for the chevron-lovers

<input type='file' name='files[]' />

CoffeScript

s3upload = s3upload ? new S3Upload
    file_dom_selector: '#files'
  s3_sign_put_url: '/signS3put'
    onProgress: (percent, message) ->
        console.log 'Upload progress: ', percent, message # Use this for live upload progress bars
    onFinishS3Put: (public_url) ->
        console.log 'Upload finished: ', public_url # Get the URL of the uploaded file
  onError: (status) ->
    console.log 'Upload error: ', status

or JavaScript for the brace-lovers

var s3upload = s3upload != null ? s3upload : new S3Upload({
  file_dom_selector: '#files',
  s3_sign_put_url: '/signS3put',
  onProgress: function(percent, message) { // Use this for live upload progress bars
    console.log('Upload progress: ', percent, message);
  },
  onFinishS3Put: function(public_url) { // Get the URL of the uploaded file
    console.log('Upload finished: ', public_url);
  },
  onError: function(status) {
    console.log('Upload error: ', status);
  }
});

Be sure to set the right DOM selector name file_dom_selector for file input tag, #files in our case. s3_sign_put_url is an end-point on your server where you will be signing S3 PUT requests.

3. Server-side request signing

Be sure to set S3_BUCKET_NAME,S3_SECRET_KEY,S3_ACCESS_KEY. Create a bucket and get the keys under Security Credentials menu in AWS management console.

S3_BUCKET_NAME = 'CREATE_A_BUCKET_AND_SET_THE_NAME_HERE'
S3_SECRET_KEY = 'GET_THIS_IN_AWS_CONSOLE'
S3_ACCESS_KEY = 'GET_THIS_IN_AWS_CONSOLE'

get '/signS3put' do
  objectName = params[:s3_object_name]
  mimeType = params['s3_object_type']
  expires = Time.now.to_i + 100 # PUT request to S3 must start within 100 seconds

  amzHeaders = "x-amz-acl:public-read" # set the public read permission on the uploaded file
  stringToSign = "PUT\n\n#{mimeType}\n#{expires}\n#{amzHeaders}\n/#{S3_BUCKET_NAME}/#{objectName}";
  sig = CGI::escape(Base64.strict_encode64(OpenSSL::HMAC.digest('sha1', S3_SECRET_KEY, stringToSign)))

  {
    signed_request: CGI::escape("#{S3_URL}#{S3_BUCKET_NAME}/#{objectName}?AWSAccessKeyId=#{S3_ACCESS_KEY}&Expires=#{expires}&Signature=#{sig}"),
    url: "http://s3.amazonaws.com/#{S3_BUCKET_NAME}/#{objectName}"
  }.to_json
end

Resources

The code is a based on these resources, but has been put in to an easy to use CoffeeScript/JavaScript Class

You can learn more about CORS here

Rok Krulec / @tantadruj