Precompiling with Heroku

As Standards has progressed, I’ve ended up with a lot of CoffeeScript, Javascript and LESS files. I came to depend on require.js not only for its module management but it’s great, integrated r.js build step. less.js serves the same purpose for stylesheets.

On Heroku, using Git to deploy code, I found myself commiting compiled JS and CSS in order to deploy it. Maybe you just shook your head and thought “Nuh-uh! I’d never commit that code to master, I’ve got a deploy branch that handles compiled code!“ Well, sure. There wasn’t a great way to handle the missing build step in between developing locally and pushing to a Heroku box until Rails 3.1 introduced the Asset Pipeline. But what happens if you’re not using Rails 3.1? Standards is a Sinatra app after all.

Turns out there are a few trickle-down effects from Heroku’s support for the Asset Pipeline that apply to all Ruby apps. After pushing code to Heroku, the Ruby buildpack will look for an assets:precompile rake task. If this task is detected the build pack will vendor Node.js and put it in the path of your app. This is important because, although Heroku supports Node.js apps, you don’t normally have access to it if you’re running a Ruby app. These are the two pieces necessary to move the require.js and LESS build steps onto Heroku.

I won’t go into the details of setting up require.js, it’s own website is a good resource, but compiling on Heroku doesn’t require any changes to be made to the normal build process.

I’ve borrowed the Rakefile from the requirejs-rails gem and stripped out most of what has to do with the Asset Pipeline or Sprockets. What remains is a barebone task that properly runs r.js and less.js on your code.

It’s not a particularly flexible or robust solution, but it does the trick because the configuration is handled inside of require.js.

There is one gotcha that can crop up with running this task on Heroku. The production environment is not up and running when this Rake task is run which means that the environment variables aren’t there. This is usually an issue with anything that connects to a database or tries to detect the current environment with RACK_ENV, so make sure those tasks (if any) are in a different rakefile. If not, the task will fail silently and you’ll be left wondering why your site is style-less. As of me typing this, Heroku has an experimental feature they’re testing that makes env variables available, but it’s probably easier to keep this compile task isolated.

After committing this new Rakefile and pushing the changes up to Heroku, you should hopefully see Running: rake assets:precompile in your console. This is exactly what we want, and now you can also git rm any compiled files from your repo and never worry about them again.

So what does this all do? With one Rake task you get all of the benefits of require.js for JavaScript development and keep compiled JS/CSS out of the codebase. And you can use it with any Ruby app on Heroku.

Let me know what you think, I’m @interstateone on Twitter.