Growing Devs

Apr 09, 2014

Use Bower for managing front-end assets in Rails

by Dave Copeland

Rails' history with front-end asset management is somewhat complex, involving a mixture of gems and manual file management. Fortunately, there's now a better way—Bower.

Rails 4.0.4 depends on version 2.2.x of the jquery-rails gem which in turn bundles 1.9.1 of JQuery. Does that make any sense? The latest official release of angular-ui-bootstrap-rails is 0.9.0, which is at least a version behind the current release of the Angular UI bootstrap directives. When will it be updated? chosen-rails version 1.1.0 bundles an old version of chosen-jquery that has never been officially released. What?

As recent as a year and a half ago, this mess was the only sane way to manage front-end assets in a Rails app. You'd have to create a Rails Engine inside a gem that made the assets available.

When you want to use an asset in your Rails app, you have to navigate the insanity above to figure out what version you are using. If what you want isn't provided by a gem, the “best practice” was to just download the files and throw them in vendor/assets. If your assets had inter-dependencies, you better watch out. And if you had a non-Ruby application - forget about it.

Now, there's a better way—Bower.

Bower was created by Twitter to manage front-end assets. It's not particular to Rails (and, like many JavaScript command-line tools, it uses NodeJS), but it works similarly to RubyGems and Bundler. You simply create a file in your project that describes what packages you want, and use the bower command-line app to install them. Bower also knows about inter-asset dependencies. Most importantly, Bower allows you to specify directly what version of an asset you want.

I'm not sure why Rails doesn't provide a better tool for this. Perhaps someday it will, but for now, Bower is going to make your life so much easier, especially if you use a lot of front-end assets, or need to share private assets between your apps.

Setting it up

The handy bower-rails gem creates some Rake tasks for you, but also allows you to specify your dependencies in a succinct Gemfile-like format (called, naturaly, Bowerfile).

In your Gemfile:

gem 'bower-rails'

It's important to note that this doesn't include the bower command-line app, it just calls into it. You'll need to install bower, likely with npm install bower (which requires installing Node and NPM. I know that's a potential yak-shaving thing, but it'll be worth it).

Then place Bowerfile in your root directory. Here's an example of one that uses AngularJS, version 1.2.13:

asset 'angular', '1.2.13'
asset 'angular-route'
asset 'angular-resource'
asset 'angular-mocks'
asset 'angular-ui-bootstrap-bower'

You then install them with rake bower:install. If there are any verison incompatibilities, they will generate errors, just like you'd see in Bundler. Everything gets downloaded to vendor/assets/bower_components by default. Because this isn't standard Rails, you'll need to add this to your asset pipeline configuration in config/application.rb:

config.assets.paths << 
  Rails.root.join("vendor","assets","bower_components")

And, finally, add your newly-managed assets to application.js:

//= require angular/angular
//= require angular-resource/angular-resource
//= require angular-route/angular-route
//= require angular-ui-bootstrap-bower/ui-bootstrap.js
//= require angular-ui-bootstrap-bower/ui-bootstrap-tpls.js

That's it! Now, your front-end assets can be managed in a sane way. But this is only part of it. Because Bower is so simple, it's easy to use it to manage internal, private assets that you don't (or can't) share with the outside world.

Managing Private Assets

I work at Stitch Fix, and we have several applications that serve many different purposes. Still, they all interact with our inventory in various ways. Although much of that information is stored in a shared database, the official color swatches of our inventory aren't stored there. They had been copied between various apps. We're now using Bower to share them. This way, when we add new colors or update the swatches, the whole team knows, and we can roll out the updates in an organized way.

Here's how to set that up.

Since a Bower version string can be a git url, a value like git@github.com/stitchfix/colors#1.0.3 will tell Bower to get assets from the stitchfix/colors repo, at whatever version is tagged 1.0.3. All we have to do is put a small file named bower.json into that repo:

{
  "name": "colors",
  "version": "1.0.3",
  "main": [
    "colors.css"
  ],
  "dependencies": { },
  "devDependencies": { },
  "ignore": [
    "**/.*",
    "bower_components",
    "test"
  ]
}

In your Bowerfile, you just use the git url:

asset 'colors', 'git@github.com/stitchfix/colors#1.0.3'

And, we add it to application.css.scss:

#= colors/colors

That's it! Now you can manage internal assets without RubyGems in a sane way. This means that all your front-end assets, public and private, are managed from one clear location, and you can re-use your internal assets for non-Ruby apps, to boot.

Next time you are tempted to use curl to manage your assets, try Bower instead.