« Which do you believe, the map or the GPS? | Main | What if? »

Now I know a little more about rake-pipeline

I’ve been doing a lot of work recently with a Javascript framework called Ember.js. In production, it asks the user to load a single Javascript file up front, and then runs the whole application in the browser. With a medium-sized or bigger project, you need some kind of build toolchain to take the many smallish code files you’re working on and bundle them up, both for production and also on an ad-hoc basis as you’re working. The toolchain I’m using is called rake-pipeline (rakep for short) which is just some sugar layered over rake which is really just ruby scripting.

If you haven’t glazed over yourself by now, bear with me.

(Aside: All of this stuff has been generated by a culture of companies, mostly but not exclusively on the West Coast, building tools for their own use and then publishing the good stuff—whatever’s not central to their real business—free, open-source, for everyone else’s benefit. It’s pretty awesome and I try to contribute my own tweaks back when I can.)

If you haven’t used Ruby but are familiar with software, Rake is just make in Ruby. rakep reads an Assetfile which is the equivalent of Rakefile in Rake or Makefile in make. I hadn’t seen the syntax before but I could sort of suss out what was going on.

I’ve been using git post-commit hooks to generate a one-line Javascript file which contains a “version string” that’s just the hash of the most-recent git commit. Displaying this string in the application helps me tell if I’m looking at the most-recent version of the code, or an older build. However, if someone else doesn’t have my hooks installed, that file isn’t generated, and their application won’t load. I needed a better way.

First I looked at Flame.js, a widget library for Ember which I’ve contributed to several times over the last few months. Flame generates a version constant by generating a temporary version.js file in ERb, Ruby’s built-in template language, using Ruby to send git describe --always --dirty --tags to the shell and planting that in a temporary .js file. Flame, however, uses its own Rake tasks to build its distribution versions, and runs Sprockets over all the input files to handle Sass, and rakep uses neither Sprockets nor Sass, (at least not explicitly). I couldn’t just borrow stuff from their Rakefile, nor could I drop an .erb file into my code directory and expect it to Just Work.

I looked at the filters that were included, and discovered that Yehuda Katz’s rake-pipeline-web-filters library (which was already in use - Katz is a core team coder for Ember) includes a Tilt filter. Tilt is a sort of “send me anything and I’ll decode it” filter, and it will handle ERb. So I explicitly required Tilt in my Assetfile, and added this block before encoding of Javascript began:

  match 'lib/version.js.erb' do
    filter WebFilters::TiltFilter do |input|
      input.sub(/.js.erb/, '.js')
    end
  end

What that wound up doing was taking my version.js.erb file and generating a temporary version.js file which was then included along with the rest of the files as though it had been there all along. It’s not in with my regular code, so it doesn’t get committed to git itself, but it’s included in all the build files. And because the Assetfile is part of the project itself, anyone who builds the project (and has included all the requisite gems, has the right versions of Ruby, etc. etc. which they probably do if they’re building this) will get the appropriate version string in the application.

It’s a little thing, but I’m sort of proud of it. I could probably make that first line match 'lib/*.js.erb' and have it work on any .erb file in the directory, but it’s not needed so I won’t bother.

Post a comment