Speeding Up Your Webby Site With Juicer

On this blog I use several stylesheets to keep things (somewhat) organised. This allows me to upgrade my coderay.css file or my Tripoli CSS stylesheets without having to reorganise everything.

But, just because I like to organise my code into managable chunks, doesn’t mean that I have to degrade the performance of the site for the visitors.

To help me improve performance by both reducing total transfer size and amount of requests for stylesheets, I’ve added Juicer to the mix.

Juicer requires a few gems and Java (as it uses YUI Compressor internally to minify stylesheets), but if you’re still reading, this should not be a problem for you.

The stylesheets

Firstly, I’ve created two driver stylesheets, that is responsible for importing the other stylesheets in the correct order.

First, the stylesheet for modern browsers.

1 /* master.modern.css - holds stylesheets for modern browsers */
2 @import url(/stylesheets/tripoli/tripoli.simple.css);
3 @import url(/stylesheets/coderay.css);
4 @import url(/stylesheets/base.css);

Second, the stylesheet older versions of Internet Explorer

1 /* master.ie7.css - loads stylesheets for IE7 and lower */
2 @import url(/stylesheets/tripoli/tripoli.simple.css);
3 @import url(/stylesheets/tripoli/tripoli.simple.ie.css);
4 @import url(/stylesheets/coderay.css);
5 @import url(/stylesheets/base.css);
6 @import url(/stylesheets/ie7.css);

Steve Souders has explained that you should not use @import in your stylesheets, as it will block parallel downloads. But, don’t worry, Juicer will combine all of these stylesheets into one and all will be well in the world.

The rake file

To control the behaviour of Juicer, I’ve created a little rake task.

 1 # juicer.rake
 2 namespace :juicer do
 3   namespace :merge do
 4     desc 'Merges stylesheets'
 5     task :stylesheets do
 6       sh 'juicer merge content/stylesheets/master.modern.css -o content/stylesheets/master.modern.min.css --document-root content --force'
 7       sh 'juicer merge content/stylesheets/master.ie7.css -o content/stylesheets/master.ie7.min.css --document-root content --force'
 8     end
 9   end
10 end

You should update the rake task with the correct paths and filenames for your site.

Updating the Sitefile

In order for Webby to generate these new files, you will need to update your Sitefile, and instruct Webby to run the merge task with every build. To do this you simply add a dependency for the built-in build tasks.

 1 # add these lines to your Sitefile
 2 desc "Build the website"
 3 task :build => [:configure_basepath, 'juicer:merge:stylesheets' ]
 4 
 5 desc "Rebuild the website"
 6 task :rebuild => [:configure_basepath, 'juicer:merge:stylesheets' ]
 7 
 8 desc "Continuously build the website"
 9 task :autobuild => [:configure_basepath, 'juicer:merge:stylesheets' ]

Using the new merged stylesheets couldn’t be easier, you just reference them by their new names master.modern.min.css and master.ie7.min.css.

Results

For this blog, the result is ~2kb and 2 or 4 connection requests saved, if your site has bigger and/or more stylesheets, you’re going to see even better results.

As an added bonus, Juicer also adds cache buster suffixes to all image references in the stylesheets (this is configurable), so now I can safely turn on expiration headers for these images and my (repeat) visitors can enjoy an even faster site.

Perfect Pitch

Perfect Pitch is an article by Jeremy Keith that discusses some recent issues and misuses of DMCA unfairly to destroy competitors search engine rankings.

It all started out as an innocent comment about attaining Perfect Pitch on The Session.

This is really just another one of those examples of American legislation that got implemented without any real thought of the consequences or of how it could be misused, not entirely unlike the Intellectual Property and Patents legislation in the U.S. GO Lobbyists!!!

Help Jeremy out, and create your own Perfect Pitch post and even better, link to the other two.

Combining JavaScript Files - Juicer vs Sprockets

Currently working on a project that has well defined use of “namespaces” and structured use folders for its JavaScript files. I wanted to investigate the options for combining and minifying JavaScript files.

I need a tool that:

  • can be run from command line (my team uses many different editors and IDEs)
  • will work on both Windows and Unix based platforms
  • does not require huge, obscure configuration files
  • can merge sources recursively
  • has an acceptable software license (MIT / Apache / BSD)
  • is thorougly tested
  • is extendible
  • can work with any JavaScript framework

I settled for trying out Juicer and Sprockets, since both tools met the requirements and were the only high-quality tools on my radar.

Feel free to suggest more tools to try out in the comments.

Both Juicer and Sprockets use Ruby, so make sure you have a recent Ruby and Rubygems installed if you want to experiment with them. Most developers that care enough about good frontend performance seem to have Ruby anyway these days.

I tested the tools with Ruby 1.8.7 on OS X 10.6.1.

Juicer

License: MIT

URL: http://github.com/cjohansen/juicer

I first became aware of Juicer when Christian Johansen released the 0.2.0 version to the public about six months ago. Since then I have been wanting to try it out for work related projects.

Installation

Installation of Juicer is pretty straight forward

1 $ gem install juicer
2 $ juicer install yui_compressor
3 $ juicer install jslint

Usage

Using Juicer for JavaScript dependency management is pretty straight forward, in your code you simply specify dependencies with the @depend keyword and juiced picks up on this and merges the files automagically.

1 /**
2   * My script file
3   *
4   * @depend jquery-1.2.0.js
5   */
6   var myNS = {
7     myObject = {}
8   };

To merge the dependencies into the file you simply run

1 $ juicer merge myfile.js

This will produce a new file, myfile.min.js, which contains all dependencies merged in. It parses each dependency and resolves it’s dependencies as well. The file will be stripped of all comments and minified, this is highly configurable, if you know how to use YUI Compressor (and you should know this).

Bonus features

  • Builtin use of JsLint
  • Builtin use of YUI Compressor
  • Can merge CSS files
  • Can create cache buster urls for assets referenced by css files
  • Can cycle asset hostnames for asset urls in css files

Sprockets

License: MIT

URL: http://getsprockets.org

To my knowledge, Sprockets was released at around the same time as Juicer, both projects seemed to be blissfully unaware of each other. Sprockets is created by Sam Stephenson of Prototype fame.

Installation

Installing Sprockets is a no brainer, if you have ruby

1 $ gem install --remote sprockets

This will give you a gem, with all you need to run Sprockets, including a “sprocketize” command.

Usage

Using Sprockets for JavaScript dependency management is very easy, you specify dependencies in your source code with the //= require notation, and it will resolve the dependencies for you.

1 //= require "jquery-1.2.0"
2 /**
3   * My script file
4   */
5   var myNS = {
6     myObject = {}
7   };

To merge the dependencies in, you simply run the sprocketize command on the file, specifying where the output should go.

1 $ sprocketize myfile.js > myfile.combined.js

This creates the merged file, with all dependencies merged in, neat and to the point. Sprockets has many subtleties that allows for greater control and for easier reading of the dependency directives. Luckily, it’s very well documented, reading the documentation for the finer points is recommended.

Bonus features

  • Bundling of assets, to create release builds with all dependencies like CSS, images, flash files. Very neat.
  • Support for insertion of constants into the code (like version numbers, authors, i18n, etc)
  • Sprockets is really a well structured Ruby library, so you can just keep extending and building on it
  • Rails plugin (well, only a bonus if you use Rails)
  • CGI script for serving outside Rails

Sprockets does not come with JsLint or YUI Compressor builtin, you will have to add this to your build script yourself. This should not be that much of an issue, as you will probably want to be able to create several diffent builds for yourself anyway.

The verdict

Sprockets seem very well suited for framework authors, not surprising since it originated from the Prototype JS framework.

Juicer has some very compelling features for optimizing the use of CSS files and resources referenced by these files.

Both Juicer and Sprockets are carefully crafted tools and show great maturity. Both projects encourage contributions and are both hosted on GitHub, so collaboration is really easy.

Setting up each tool and using it for merging dependencies for a large project with many JavaScript files took me about half an hour.

I can only recommend that you try out both tools and see which one fits best with YOUR plans for World Domination™.

Installing Mercurial With Bash Completion from MacPorts

Now that Snow Leopard is out, I ran into a few issues with some of my installed ports. Upgrading them to run on the new 64-bit OS also gave me some grief.

I decided to just start over with a clean slate for all my ports.

Make sure to install the latest XCode (and perhaps Apple’s X11 from the optional installs) from the Snow Leopard DVD. Once that is done, you should install v1.8.0 of MacPorts. As usual, there are detailed instructions on the MacPorts website.

You can find details on how to uninstall your installed ports on the MacPorts wiki.

If you’re installing Mercurial from MacPorts, do get the bash_completion variant, as it’s much nicer to work with on a daily basis.

At the time of writing, python26 won’t install from MacPorts on Snow Leopard. Python 2.6 is a requirement for Mercurial. The issue is very actively being worked on by your friendly MacPorts maintainers, so just have a little patience.

While we wait patiently, you can always take the opportunity to learn more about Mercurial, there are several good resources:

Once the python26 port is working on Snow Leopard (probably fixed by the time you read this), you should treat yourself to having bash completion for Mercurial.

All you need to do to attain bliss, is just to instruct MacPorts to install the bash completion variant.

$ sudo port install mercurial +bash_completion

Such a long post for a little port statement :-)

Update: You can also install pre-built binaries while we wait for the fix to the MacPorts version, that’s what I’ve done.

Update – 2009-09-12: The awesome MacPorts maintainers have fixed python26 port some days ago, so there are no longer any problems installing Mercurial with bash completion from MacPorts.

TextMate snippet for creating Low Pro Behaviors

Behaviours

To encapsulate complex javascript behaviour on websites, I have been using Dan Webb’s Low Pro library for several years. Low Pro allows you to create self-contained Behavior classes, which avoids polluting the global namespace with variables and makes for very easy re-use of code.

I’ve previously given a little introduction to Low Pro for Prototype at a local Meetup event, where I show an example of creating your own behaviours.

Textmate snippet

Today, I finally got around to creating a TextMate snippet for creating new Behaviors.

TextMate snippets are an easy way of optimising your daily coding, by automating the writing of some of your code. They’re surprisingly simple to work with.

In the simplest case, you can use snippets to insert text that you do not want to type again and again, either because you type it a lot, or because the actual text to insert is hard to remember (like your bank account details or the HTML entities for the Apple modifier keys).

Activating the snippet and filling in the options (class name, default options, etc) will give you something like this:

/**
* class MyBehavior
* Behavior class for managing behavior of ...
* See http://www.danwebb.net/2006/9/3/low-pro-unobtrusive-scripting-for-prototype
**/
var MyBehavior = Behavior.create({
  options : {
    myOption : 'myOptionDefaultValue'
  },

  /**
  * MyBehavior#initialize( [ opts = { myOption : 'myOptionDefaultValue' }] )
  * - options (Object): Will be merged with the default options, good for 
  *   overriding texts, urls, dom references, etc
  * Gets called when the element is loaded	
  */
  initialize : function( opts ){
    this.options = (this.options).merge( opts ).toObject();
    // alert( this.options.myOption )
  }
);

The snippet is available on github, should you feel the need to customize or improve it or you can just download the snippet now.

Creative Commons License