Javascript is sad
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.
Javascript is happy!
Sprockets is a 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.
- Use it as a Ruby library, so you can create your own JavaScript build system.
- Use the 'sprocketize' utility from the command line, for easy shell scripting.
- 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.
Sprockets is distributed as a gem, so installation is easy:
$ gem install --remote sprockets
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
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)
Move your javascript files
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
Replace your old JavaScript include tags
Our old JavaScript files are going to be concatinated 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>
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 juggernaut 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 WISWYG 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 wat 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