johndesu

Using Sprockets to Precompile Assets in a Rails Engine

July 3rd 2013

I work on extensions (plugins) for Spree quite often. Extensions are Rails engines and thus, don’t have access to the complete suite of rake tasks that rails gives you. Recently, I needed to write tests for an extension that included a Backbone.js application written in Coffeescript. Let me first explain my dilemma, and then how I went about solving it.

If my extension was a complete rails app, I’d be able to use a gem like jasminerice to handle testing my coffeescript with Jasmine. Unfortunately, I can’t guarantee the presence of a live rails app to test against with this extension. I could test against the dummy app common in Rails engines, but using jasminerice with it would require some modifications to the dummy app itself. Rather than dive into the reasons why the dummy app didn’t fit my need, I’ll just skip straight to the solution.

I decided that the simplest way for me to test my coffeescript was to precompile and minify all the files in my assets/javascripts folder using Sprockets and to test against that using Jasmine’s standalone spec runner. Far from perfect, but it would get me writing specs for my javascript quickly and that was what was important to me at the time.

So here are the two techniques I came up with:

Manually Run a Rake Task

First up, is a rake task I can run to manually precompile the assets for the engine to public/application.min.js. The following rake task can be added to your Rakefile and run with rake assets:compile.

namespace :assets do
  ROOT = Pathname.new(File.dirname(__FILE__))
  LOGGER = Logger.new(STDOUT)
  APP_ASSETS_DIR = ROOT.join("app/assets")
  PUBLIC_ASSETS_DIR = ROOT.join("vendor/assets")
  OUTPUT_DIR = ROOT.join("public")

  desc 'Compile assets'
  task :compile => :compile_js

  desc 'Compile javascript'
  task :compile_js do
  outfile = Pathname.new(OUTPUT_DIR).join('application.min.js')

    sprockets = Sprockets::Environment.new(ROOT) do |env|
      env.logger = LOGGER
    end

    sprockets.append_path(APP_ASSETS_DIR.join('javascripts').to_s)
    sprockets.append_path(PUBLIC_ASSETS_DIR.join('javascripts').to_s)

    FileUtils.mkdir_p outfile.dirname
    asset = sprockets['application.js']
    asset.write_to(outfile)
    puts "Compiled JS assets"
  end
end

The important line to note in the above rake task is asset = sprockets['application.js']. You’ll want to make sure to point to your manifest file in that line, so Sprockets will know which files to precompile and in what order to precompile them.

The above rake task is also available in a gist.

Use guard-sprockets to Automatically Precompile Assets

The second method I came up with was to use guard-sprockets to automatically monitor my assets directory and precompile whenever I changed any of my application’s coffeescript.

Here’s how I configured my Guardfile:

guard 'sprockets', :destination => 'public', 
  :asset_paths => ['app/assets/javascripts', 'vendor/assets/javascripts'], 
  :root_file => 'app/assets/javascripts/application.js', :minify => true do
  watch(%r{^app/assets/javascripts/(.+)\.(js|js\.coffee)})
end

The above Guardfile is also available in a gist.

blog comments powered by Disqus