Feb 5 2007

Minifying Your Rails Javascript

While Prototype and Scriptaculous prove to exceptionally useful, they both have a pretty substantial footprint. The current stable Prototype (v1.5) is 69K, and the Scriptaculous Effects library is 36K. This puts us at over 100K to include these Javascript libraries.

This number can be cut down a little bit with Douglas Crockford’s JSMin filter. This filter creates a smaller version of your Javascript source by stripping out extraneous code like whitespace and comments. The minified versions of Prototype is 52K, and Effects is 28K. This saves us around 25K off the bat.

Since we like to keep as much of our code as possible in the Ruby family, we use the Ruby version of the minifier. Copy The jsmin.rb file to script/javscript/jsmin.rb in your Rails application.

Now let’s add a handy Rake task to minify your javascript code using this script. The following task will combine prototype.js, effects.js, and application.js. This will create our final minified file as all_min.js. You can add additional javascript files to the libs array as needed, or adjust what you want the final file to be named. Then copy the code into a file named lib/tasks/js.rake.

namespace :js do
  desc "Minify javascript src for production environment"
  task :min => :environment do
    # list of files to minify
    libs = ['public/javascripts/prototype.js', 
    # paths to jsmin script and final minified file
    jsmin = 'script/javascript/jsmin.rb'
    final = 'public/javascripts/all_min.js'
    # create single tmp js file
    tmp = Tempfile.open('all')
    libs.each {|lib| open(lib) {|f| tmp.write(f.read) } }
    # minify file
    %x[ruby #{jsmin} < #{tmp.path} > #{final}]
    puts "\n#{final}"

Before we run the task, there is a single point in Prototype version 1.5 stable that breaks the jsmin filter. There is a patch for this in the Rails trac, but we will need to manually add the single missing semi-colon until it is applied. You may want to also run your application code through JSLint Verifier and clean up any issues that may jam the jsmin filter.

Now we can minify our javascript by running this new task. It will create a new javascript file with the combined source. From the root of your rails application run:

$ rake js:min
(in /Users/derek/work/sportspyder/trunk)
created public/javascripts/all_min.js
In our development environment we don't want to have to re-minify our javascript after every change. We'll still use our separate and easy to read source files. We can do this by putting a conditional in our layout to include the minified version in production mode, and the separate files during development.
<pre lang="ruby">
<% if RAILS_ENV == 'production' %&gt;
<%= javascript_include_tag "all_min" %&gt;
<% else %&gt;
<%= javascript_include_tag "prototype", "effects",
                           "application" %&gt;
<% end %>

One of the added benefits of this approach is that you have a single Javascript source file for the client to download instead of multiple resources for the browser to pull.

You’ll have to make sure to run this rake task before you deploy, and may want to add it directly to your deployment script.

While minification provides a nice break in file size, it is secondary to sending your javascript compressed. Compression can cut your Javascript to nearly 1/4 of the original size, and is most commonly done using using Apache’s mod_deflate module. There is more information on Apache settings on the Mongrel website.

Update – 03/01/2007

Prototype doesn’t actively support a specific packing strategy for various reasons, and patches submitted for making the code pass something like JSLint are likely to be ignored. Reasons for this, and some other strategies on reducing filesize of the library are discussed in Packing Prototype.

Update – 12/14/2007

Rails 2.0 includes a feature that makes much of what is described here obsolete. Check out our write-up of Rails Asset Cache.

Post a comment