Friday, January 18, 2008

Merb: Multiple CSS files, one server request.

In my previous post Continued Education: Performance Yahoo I referred to Steve Souder' book "High Performance Web Sites".

Rule #1 is "Make fewer HTTP requests."

Now we already know that Merb is "built for speed", but generally that is considered within the context of the server side of things.

I was happy to see that Merb also allows us to follow Souder's #1 Rule for making the client side snappy too. So how does Merb allow us to make fewer HTTP requests? By dynamically combining multiple stylesheet or script files into one.

Let's see some code!
It's this simple:

# app/views/layout/application.html.erb
<% require_css :reset %>
<% require_css :master %>
<%= include_required_css :bundle => true %>
We define the various CSS files we wish to be included using require_css (in this example reset.css and master.css), then by setting the :bundle => true paramenter everything will be served up in a single HTTP request in a file called all.css! Now that's pretty cool.

But wait there's more!
The same technique works for Javascripts too.
You can have the same functionality for your javascripts using this syntax:
<% require_js :foo $>
<%= include_required_js :bundle => true %>
But wait there's even more!
Now what is really cool is that you don't have to place your require_css or require_js statements only in the layout. You can place those in your views or even partials. That means that for any given request, the bundled file will only include the files that are needed for that specific view. Edit: It looks like you may need to manually define and uniquely name each possible combination of files. It also appears that a CSS file required in a view will appear first in the generated combined CSS file and thus be over ridden by the (likely) more general file defined in the layout - which probably isn't the desired behavior.

Getting it to work
By default the bundling action should only occur when in production mode. At the moment (Merb 0.5.2) it appears there is a bug and the bundling action doesn't realize when it is in production mode - so nothing happens.

What you need to do is edit your config/merb.yml file and uncomment the line that reads:
:bundle_assets: true
That's it! Should work. Enjoy.

One Gottcha
By forcing :bundle_assets to true in the merb.yml file, we are enabling this functionality for all environments instead of just for production. This isn't really ideal

Thanks to dudleyf in #merb for helping me figure this out. Thanks to codahale for writing the code for :bundle.

1 comment: