Sass, Compass, and the Rails 3.1 Asset Pipeline

Note: Today's guest post is courtesy of Wynn Netherland, CTO at Pure Charity in Dallas and co-author of Sass and Compass in Action, a CSS book. He's a web designer and a front-end developer, as well as a CSS geek. Check him out on GitHub and Twitter.

TL;DR

Compass and the Rails 3.1 Asset Pipeline can play nice to improve how you create, maintain, and serve stylesheet assets, but you'll may need to tweak your setup to boost speed during your stylesheet development.

Since the advent of dynamic web pages, there has remained a dichotomy in web development. Developers tend to keep server-side code and templates in one spot and all the other static images, stylesheets, and client-side scripts in another. Agency-driven, split team workflows in which designers hand off static pages to web developers to break them into server-side templates have reinforced this model. We even call our stylesheets, images, and scripts assets, as if they were meant to be deposited into our /public folder, not to be handled with our application code. The Rails 3.1 Asset Pipeline breaks down this firewall and makes static assets first-class citizens in your web application. While it also handles images, CoffeeScript, and many other content types, let's explore what the asset pipeline does for stylesheet authors.

What does the Pipeline do for me?

For serving CSS, the asset pipeline performs a few key functions.

Concatenation. Stylesheets can be stitched together from multiple source files, reducing the number of HTTP requests for CSS assets. The default application.css in Rails 3.1 is a manifest and tells the pipeline which source files to concatenate and serve to the browser:

/*
 * This is a manifest file that'll automatically include all the stylesheets
 * available in this directory and any sub-directories. You're free to add
 * application-wide styles to this file and they'll appear at the top of the
 * compiled file, but it's generally better to create a new file per style scope.
 *= require_self
 *= require_tree .
 */

By default, all stylesheets will be included. Sprockets, the gem that powers the pipeline, allows for more granular control:

/*
 *= require vars
 *= require typography
 *= require layout
 */

Just like view partials, we now get the benefit of organization by splitting up large stylesheets across several source files.Minification. Whitespace and comments are removed from stylesheets before getting served up to the browser, reducing file size.

Fingerprinting. In Rails 3.1, cache-busting fingerprinting is baked right into the asset filename instead of relying on querystring parameters which have drawbacks in multi-server environments and some transparent proxy servers.

Pre-processing. Perhaps the biggest feature of the asset pipeline is preprocessing. Stylesheets can now be authored in Sass, Less, even ERB (gasp!), introducing dynamic methods to create static stylesheets.

Compass in the pipeline

Many of the above benefits have been available previously with Compass, the stylesheet framework for Sass. It's no surprise that someone recently asked on the Compass mailing list if Compass was somehow obsolete with the arrival of the asset pipeline.

While it is true that there is some overlap in functionality between Compass and the asset pipeline, Compass does so much more. In addition to concatenation, minification, and preprocessing via Sass, most importantly Compass provides powerful modules for common stylesheet tasks including:

  • CSS3. The Compass CSS3 module provides Sass mixins for CSS3 features, allowing you to target multiple browsers' vendor namespaces using a single syntax.
  • CSS sprites. Reducing the number of HTTP requests is a key factor of web application performance. The sprite helpers will create CSS sprites from a folder of separate assets, handling all the geometry for sprite layout, allowing you to reference icons by name.
  • Grid frameworks. Compass has great support for Blueprint, 960.gs, Susy, Grid Coordinates, and more.
  • Typography. Compass makes it easy to create and maintain vertical rhythm, tame lists, and style links with its typography helpers.
  • Plugins and so much more. There is a growing list of community plugins that make it easier to package styles for use across projects.

Installation

To use Compass inside the asset pipeline, be sure to add Compass version 0.11.0 (or edge if you're brave) to the asset group in your Gemfile:

group :assets do
  gem 'sass-rails',   '~> 3.1.4'
  gem 'coffee-rails', '~> 3.1.1'
  gem 'uglifier',     '>= 1.0.3'
  gem 'compass',      '~> 0.11.0'
end

Once you've updated your gem bundle, you can now use Compass mixins in your stylesheets.

Changes for Compass users

If you've used Compass prior to Rails 3.1, there are some changes you should be aware of when using Compass in the asset pipeline.

Choose a bundling option. First, decide if you want to let Sprockets manage your stylesheet bundles or simply use Sass partials. You can use Sprockets manifest require and include directives in your Sass files, however there is a simpler approach to include CSS assets in your stylesheets. Simply rename any CSS files to use the .scss. file extension and you can use them as partials in your Sass stylesheets, even if your main stylesheets use the indented syntax and .sass extension.

Watch your assets. If you use the Compass helpers image-url, font-url, etc., note that these helpers will now resolve to /assets instead of /images and /fonts. This means you'll need to put your images and fonts in app/assets/images and app/assets/fonts respectively instead of their previous homes in the public folder.

Optimizing for development

For all of its features, the asset pipeline comes with tradeoffs. The biggest impact is speed. With the asset pipeline, the entire Rails stack is loaded on each asset request. For small applications, this is trivial. For larger applications with many gem dependencies (especially those employing Rails engines) where many classes are reloaded with every request in the development environment, assets may render much more slowly when rendered via the asset pipeline.

Tweak your setup

If slow asset compilation is slowing down your front-end development, take a look at the rails-dev-tweaks gem from Wavii. The gem provides the ability to tweak Rails' autoload rules, preventing reloading between requests in development. The default rules skips reloading classes for asset, XHR, and favicon requests:

config.dev_tweaks.autoload_rules do
  keep :all

  skip '/favicon.ico'
  skip :assets
  skip :xhr
  keep :forced
end

You should notice a speed bump, but keep in mind that if you have custom Sass functions, you'll want to bounce the server to see those changes.

Precompile engine assets

You can speed up your development environment considerably by precompiling assets as you would in production, effectively bypassing the asset pipeline altogether. While this is encouraged for team members who aren't modifying stylesheets, it doesn't help stylesheet authors much. There is one noticeable exception - Rails engines.

Rails engines like Devise, Spree, and Refinery are powerful. Just by configuring a gem and running a generator you can add authentication, storefront, or CMS features to your Rails app with little effort. If your app uses engines, and you find your development environment begins to slow to a crawl, make sure your engine assets aren't clogging the pipeline. In the case of Spree, we can improve asset performance by precompiling assets with a Rails Rake task:

rake assets:precompile RAILS_ENV=development RAILS_ASSETS_NONDIGEST=true

This will compile all application assets into /public/assets, allowing Rails to serve them without needing to recompile on each request:

drwxr-xr-x  17 wynn  staff   578 Nov  2 08:36 .
drwxr-xr-x   8 wynn  staff   272 Nov  2 08:35 ..
drwxr-xr-x  16 wynn  staff   544 Nov  2 08:36 admin
-rw-r--r--   1 wynn  staff   155 Nov  2 08:30 application.css
-rw-r--r--   1 wynn  staff   143 Nov  2 08:30 application.css.gz
drwxr-xr-x   7 wynn  staff   238 Nov  2 08:36 creditcards
drwxr-xr-x   3 wynn  staff   102 Nov  2 08:36 datepicker
-rw-r--r--   1 wynn  staff  1150 Nov  2 08:19 favicon.ico
drwxr-xr-x   6 wynn  staff   204 Nov  2 08:36 icons
drwxr-xr-x   4 wynn  staff   136 Nov  2 08:36 jqPlot
drwxr-xr-x  15 wynn  staff   510 Nov  2 08:36 jquery-ui
drwxr-xr-x   3 wynn  staff   102 Nov  2 08:35 jquery.alerts
drwxr-xr-x   3 wynn  staff   102 Nov  2 08:35 jquery.jstree
-rw-r--r--   1 wynn  staff  6694 Nov  2 08:36 manifest.yml
drwxr-xr-x   5 wynn  staff   170 Nov  2 08:36 noimage
-rw-r--r--   1 wynn  staff  1608 Nov  2 08:19 spinner.gif
drwxr-xr-x   6 wynn  staff   204 Nov  2 08:36 store

With precompiled assets, our load times are reduced dramatically, however we won't see changes to our own stylesheets. In the example above, we can simply remove application.css and application.css.gz so that those will be compiled on each request via the asset pipeline. However, having our engine-provided stylesheets precompiled is a big win.

As we mentioned above, one of the big gains of the asset pipeline is concatenating our stylesheets into a reduced number of files. If you are serving multiple application-specific stylesheets, consider precompiling all your assets and then removing your current work-in-progress stylesheet from /public/assets.