← Home

Rails plugin: Blazing fast page loads through bundled CSS and Javascript

What does it?

Basically, what the plugin does is:

  • combine multiple CSS or Javascript files into one big file (bundle) on the fly
  • compact this bundle by removing whitespace, comments and the like
  • cache the bundle by using Rails default page caching mechanism
  • create an "accesspoint" to the bundle by adding an appropriate route

It thereby removes the HTTP overhead for requesting several CSS and Javascript files to probably just request one CSS stylesheet and one Javascript file. There are some firebug screenshots in the Sitepoint article linked above which demonstrate quite nicely how significant this load overhead is in terms of user (speed) experience.

How to access the bundles?

Rakaz proposes the following syntax in his article to define a bundles contents and access them through an URL:


http://example.org/bundle/one.css,two.css,three.css

... which I think is ok, but can be done more concise - we don't really need the repetition of .css because we wouldn't allow to combine CSS files with JS or other filetypes anyways.

It makes sense though to append the information that we're dealing with CSS files here as a regular file extension (.css) because this helps with webserver configurations and the like. So this is preferable over:


http://example.org/bundle/css/one,two,three

Also, following Rails conventions with plural directory names like "stylesheets" and "javascripts" the better choice is "bundles" rather than "bundle" within a Rails plugin. So, combining these considerations I settled with this synatx:


http://example.org/bundles/one,two,three.css

What will be bundled?

Now, if you access the URL above and there are the files one.css, two.css and three.css in your public/stylesheets directory, the plugin will combine them into a single bundle file, compress them and page-cache them for future requests in the public/bundles directory.

If there's a subdirectory one (instead of a file one.css), a recursive glob will be performed and and all CSS files in the subdirectory (and recursively all of its subdirectories) will be collected and merged into the bundle as well. This makes sense when you have a large number of separate files: you can access them through their directory name then.

If there's no correspondent file one.css or directory one at all this part silently will be ignored.

How does the compression work?

It's not really compressed, but compacted. I haven't build in any gzip/deflate compression because I can use Apache's mod_deflate for this task. This could be added easily though I guess.

Instead the plugin uses:

... to remove whitespace, comments and the like from Javascript and CSS files.

How to install?

You can install this plugin simply by using Rails script/plugin installer. Standing in your Rails root directory do:


script/plugin install http://svn.artweb-design.de/stuff/rails/bundled_assets/

Also, up to now you'll have to add a route to your routes setup manually. Therefor edit your config/routes.rb file and add the following line (somewhere above Rails' default routes):


map.connect 'bundles/:names.:ext', :controller => 'assets_bundle', :action => 'fetch', :ext => /css|js/, :names => /[^.]*

How to use?

After you've successfully installed this stuff (do not forget to restart your server) you can use it in your templates (again, do not forget to invalidate your page caches if necessary). E.g., the layout template of this blog contains the following lines:


<link rel="stylesheet" href="/bundles/layout,styles,search-tag.css" type="text/css" media="screen" charset="utf-8" />
<script src="/bundles/prototype,tools.js" type="text/javascript" charset="utf-8"></script>

Update: In the comments, Nick Pearson posted a super-useful tip about how to use this plugin together with the built-in Rails helpers for javascripts and stylesheets. I've posted a separate article about this setup here: How to use the Bundled assets plugin with Rails' built-in tag helpers.

Possible improvements? Problems?

Besides integrating basic gzip output compression the plugin could use some configuration options such as whether or not subdirectory contents should be bundled, whether or not the code should be compacted (and how).

Update:In the meantime some work has been done and some of these options have been added. See this article (also for much improved performance through a compiled version of JSMin): Serve CSS and Javascript even faster: improved Rails bundled_assets plugin.

Also, there's currently no solution for a possible problem with relative image URLs in CSS files that are bundled from within subdirectories (and this way "transferred" to upperlevel directories). Using absolute URLs should work in this case though.

Feedback?

What do you think?