Rails 3.1 and asset pipeline

When we heard the announcement of Ruby on Rails 3.1 RC, we agreed that we upgrade one of our internal applications and check out all of the new features.
This of course meant porting all of our asset packing and management from Jammit to Sprockets backed asset pipeline. Everything didn’t go as smooth as expected though.

The first issue I encountered with assets was that they were only concatenated in production, but not minimized or packed or anything like that. Now as we didn’t generate a new blank Rails 3.1 application, we missed out on some critical configuration variables (and the documentation on the new stuff is understandably pretty sparse at the moment). So to enable any kind of compression for your assets, you need to add the following configuration statements to your environment specific configuration file (these are default values in 3.1 applications).

  config.assets.js_compressor  = :uglifier
  config.assets.css_compressor = :scss

I did a little of poking around in the source and it seems that in addition to Uglifier, you can also use YUI Compressor and Closure Compiler as Javascript compressor backends.

Now the second issue was a bit more weird – only a really small subset of the assets were being compiled with rake assets:precompile.
I spent quite a lot of time tracking the cause for this behavior and finally stumbled upon the configuration for the assets feature:

  @assets.precompile = [ /w+.(?!js|css).+/, "application.js", "application.css" ]

The regexp is meant to find all of the non-css and non-js files in the asset paths and compile them – I’m guessing that this is mainly to handle SCSS and CoffeScript files (again the documentation is hard to come by).
As an unexpected side-effect it’s matching files like jquery.min.js and jquery.autocomplete.js, but not top-level assets like admin.js, which does not really seem to be the desired behavior.

There are basically two ways asset compiling would make sense:

  • All of your assets get compiled: every single file from the asset path – from plain .css to .scss and .coffee files and manifests – get compiled and compressed. Then you just use whatever assets you like in your layouts.
  • Only the top-level manifests are compiled: this means the files you are explicitly linking in your layouts, stuff like application.js and admin.css and so on.

Considering that you have top-level manifest files that group all of your dependencies, you rarely need to just use one single asset so I decided to go with the second option.
In order to only compile the top-level manifest files, you need to avoid the built-in regexp from being run and define the files your want to compile manually.

  # config/environments/production.rb
  # just list all of your top level assets here
  config.assets.precompile = %w( admin.js admin.css)

This does seem a bit verbose (especially if you have lots of top level manifests), but I prefer this over the default broken solution or a mess of files that compiling every single asset would result in.

Still not satisfied

There is one more thing that bugs me about the asset pipeline in Ruby on Rails 3.1 – if you reference a manifest file in your layouts in development mode, you will get a concatenated resource as the output.

If you are requiring a lot of different files in your manifest, it will most definitely be annoying to debug your javascripts/stylesheets. This is where Jammit really outperforms Sprockets – you define
a resource (basically the same as a manifest) and in development mode that resource is expanded into separate files, making debugging really easy as you know exactly which file you need to check etc.
And in production the same resource is concatenated and compressed into one single, small file.

<!-- development -->
<script src="/javascripts/admin/foo.js" type="text/javascript"></script>
<script src="/javascripts/admin/bar.js" type="text/javascript"></script>

<!-- production -->
<script src="/assets/admin.js?1295621337" type="text/javascript"></script>

I feel this is the way how assets should work in Rails 3.1 by default also – the benefit is pretty clear, at least for me.

Update: So it seems you can avoid having your assets being concatenated in development like this:

  javascript_include_tag :admin, :debug => true

  # or if you want to have debugging on automatically in development
  javascript_include_tag :admin, :debug => Rails.env.development?

Thanks for the tip, Bruno Michel!

Tanel Suurhans
Tanel is an experienced Software Engineer with strong background in variety of technologies. He is extremely passionate about creating high quality software and constantly explores new technologies.

7 Comments

  • David Workman

    Don’t forget the other annoyance – if you precompile your assets in development where you don’t normally have compressors defined, then the precompiled assets aren’t compressed.

    But if you precompile in production, then your production environment needs access to the compressor, with the default of uglifier… which needs a JS runtime installed in your production environment. Not having one then causes your app to not start, which is ridiculous for something you only need once.

  • Rohit Arondekar

    You need to run rake rails:update to get the updated config files. The issues you have raised are regarding Sprockets gem which is undergoing a rewrite. More info can be found in the readme => https://github.com/sstephenson/sprockets

    I think version 2 of Sprockets should solve both your issues. :)

  • Bruno Michel

    FYI, it’s now possible to have the debug mode with `:debug => true` on `javascript_include_tag`. See http://dev.af83.com/rails/2-require-tips-rails-31-assets-bundling-sprockets/2011/06/14 for more details.

  • rtdp

    Hey,

    Thanks that
    config.assets.precompile = %w( admin.js admin.css)
    saved my day.
    Thanks.

  • phaedryx

    I think you can also put:

    config.assets.debug = true

    in your development.rb file to get the same effect.

    • Tanel Suurhans

      That is correct. At the time of writing this post, this configuration option was not available though.

  • Tamik

    config.assets.precompile = %w( admin.js admin.css) – it will ignore all the images assets.

    It is better to add this :
    config.assets.precompile += %w( manifest_admin.js manifest_admin.css )

Liked this post?

There’s more where that came from. Follow us on Facebook, Twitter or subscribe to our RSS feed to get all the latest posts immediately.