Railsmagazine60x60 Sprockets

by Starr Horne

Issue: Winter Jam

published in December 2009

Starr horne1

Starr Horne is a freelance web developer focused on making rich web applications with Ruby on Rails. He currently lives and works in Queens, NY.

You can follow starr on Twitter, or email him at starr /at/ chatspring.com.

Starr is a contributing editor with Rails Magazine where he maintains a column on client side development topics.

Introduction

It seems like JavaScript just doesn't get much love. Think about it. We have so many great tools for organizing our databases, our controllers, our HTML. But what if you want to add a little JS to the mix? Then, you're faced with an unenviable choice:

You can put all of your JavaScript into one big, unmanageable file. Or, you can use multiple files and accept the slower load times and extra complexity.

But now, thanks to Sprockets, we can have the best of both options.

Sprockets is a new project by Sam Stephenson at 37signals. It's a ruby library for managing JavaScript dependencies. With Sprockets and sprockets-rails, you can break up your JavaScript code into multiple files and directories. (Hey! That's just like a real programming language!). Then, when a page is requested, the component JS files will be assembled on the fly and served as a single file.

But what about the CSS and image files that JavaScript libraries inevitable require? The normal way of handling those is to throw them in to a subdirectory of public. But that can get messy fast.

That's why one of the most useful feature of Sprockets is the ability to create JavaScript “plugins”. Located in vendor/sprockets, these plugins let you bundle your JavaScript and its supporting assets together. A simple rake task (rake sprockets:xxx) can copy all of the assets to your public direcory, making upgrades and changes easy.

Three Delicious Flavors

There are three ways that you can use Sprockets.

  1. Use it as a Ruby library, so you can create your own JavaScript build system.

  2. Use the sprocketize utility from the command line, for easy shell scripting.

  3. Use the Sprockets-rails plugin, which makes integration with rails a snap.

We're going to focus on using the sprockets-rails plugin in this article. For more information, check out http://getsprockets.com

The Sprockets Syntax

Sprockets uses a special syntax to specify dependencies. The JavaScript interpreter simply reads the following lines as comments, but Sprockets knows better:

//= require <file> Include a file located in one of the include paths in sprockets.yml

//= require "file" Include a file based in the current directory. You can use relative paths.

//= asset asset/ Specify a path for all assets to be moved to /public

//= asset somefile.png Specify a single file to be moved.

Installing Sprockets

To install Sprockets and sprockets-rails, you'll need to make sure that you have git installed, and that you have an existing rails project to work with.

1. Install the Sprockets gem

Sprockets is distributed as a gem, so installation is easy:

$ gem install --remote sprockets

2. Install the sprockets-rails plugin

Since sprockets-rails is a rails plugin, installing it is easy as well:

$ cd your_project_directory

$ script/plugin install git://github.com/sstephenson/sprockets-rails.git

3. Configure Routes

When you install sprockets-rails, a new controller is added to your application, called SprocketsController. This controller has a single show method, which concatenates and serves your JavaScript files.

Before we can use the controller, however, we need to add a route. Once this is done, the routes.rb file should look something like this:

ActionController::Routing::Routes.draw do |map|

  # Set up routes for the sprockets-rails plugin

  SprocketsApplication.routes(map)

4. Move your old javascript files to their new home

In a normal Rails application, your JavaScript files live in the public/javascripts directory. In an application using Sprockets, they live in app/javascripts.

$ mv public/JavaScripts/* app/JavaScripts

5. Replace your old JavaScript include tags

Our old JavaScript files are going to be concatenated into a single file located at /sprockets.js. So we'll need to replace any old calls to javascript_include_tag with a single call to sprockets_include_tag.

When it's done, our layout looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

  <meta http-equiv="content-type" content="text/html; charset=utf-8" />

  <title>Rails Application With Built-In Helpdesk</title>

  <link rel="stylesheet" href="/stylesheets/main.css" type="text/css" media="screen, projection" />

  <%= sprockets_include_tag %>

  <%= yield :head %>

</head>

5. Test it out

Now you can start a test server, and open http://localhost:3000/sprockets.js in a web browser. You should see that it contains all of your JavaScript files, only concatenated.

More control

If your as big of a JavaScript junkie as I am, you'll probably find yourself with certain large chunks of code that need to be included in one page but not in another. There's no reason to include your WISIWYG editor in pages that don't use it.

Unfortunately, at the time of this writing, the sprockets-rails plugin only lets you specify one JavaScript build. Sure, you can still include the special content using plain old JS include tags. But that's not what we want.

If you'd like to see how you can modify the sprockets-rails plugin to achieve this, you can find an example at http://github.com/starrhorne/sprockets-rails/tree/master

Creating a Sprockets Plugin

Imagine for a moment, that you're Sergey Brin, co-founder of Google. The market's in a slump. Your stock is down. You've decided that the only sure fire-way to bring it up is to reimplement Google in Ruby on Rails. (Hey – it could work!)

You need to implement an autocomplete feature. And you need it to be able to easily share it between all of the Google products. In this case, a Sprockets plugin makes a lot of sense.

The anatomy of a Sprockets plugin

Sprockets plugins are pretty simple. In its simplest form, a sprockets plugin consists of a single file in vendor/sprockets/plugin_name/src

The first thing we need to do is create a directory:

$mkdir -p vendor/sprockets/autocomplete/src

And now, I'll just move my autocomplete scripts there:

$mv <some directory>/autocomplete.js vendor/sprockets/autocomplete/src

$mv <some directory>/menu.js vendor/sprockets/autocomplete/src

Using the Sprockets plugin in your rails application

We've created our plugin, but it's not much use until we tell sprockets to load it. To do this, we open app/javascripts/application.js and add the following line to the top:

//= require <autocomplete>

Declaring the plugin's dependencies

Our imaginary autocomplete.js file depends on both prototype.js and menu.js. To declare these dependencies, we'll add a few lines to the top of autocomplete.js

//= require <prototype>

//= require “menu”

Now, whenever the autocomplete.js file is included by Sprockets, it will automatically include the other files as well.

Note that the <> syntax causes Sprockets to search all directories in the include path, while the “” syntax searches the source file's local directory.

Adding assets to the plugin

Now it's time to set up the assets for the auto-complete plugin. These consist of two files: autocomplete.css and autocomplete_corners.png.

We'll create a directory to hold these. Sprockets doesn't require you to use any particular directory structure for assets, so we'll keep it simple:

$ mkdir vendor/sprockets/autocomplete/resources

$ mv <some directory>/autocomplete.css vendor/sprockets/autocomplete/resources

$ mv <some directory>/autocomplete_corners.png vendor/sprockets/autocomplete/resources

We'll add another line to autocomplete.js, to let Sprockets know about the resources

//= provide "../resources"

Now we can run rake sprockets:install_assets to copy all of the files in vendor/sprockets/autocomplete/resources to public/home

To learn more...

I hope that this article has piqued your curiosity about Sprockets. Indeed, we've only scratched the surface. If you'd like to learn more, stop by the project home page at http://getsprockets.com