Wednesday, 31 March 2010

Google Closure Compiler Advanced mode

Benefits of using Google Closure Compiler
Closure is a set of tools to help developers write javascript. At its core is a compiler designed to reduce script size drastically by shortening variables and other techniques, much like the objectives of JSMin and YUI Compressor.
At Mibbit, we serve our web based webchat client to millions of unique users every week. Written entirely in Javascript it's made up of 42 separate files totaling 428Kb so even zipped up it's responsible for over 100GB bandwidth each week.
As well as wanting to reduce our bandwidth usage, we want to make our code loads as fast as possible for users.
Why Google closure?
Closure takes the idea of a Javascript minifier a step further than ever before. It does this by doing real compilation to remove unused code, inline variables and rewrite code to make it as small as possible.
Comparison
Now lets take a look at some JS minifiers, to see how Closure compares. Note though that closure compiler is much more than a simple minifier, it also goes to great lengths to analyze program flow, re-organizing and removing unused code as much as it can.
The table below includes gzipped byte counts, because Javascript should always be served up gzipped if the browser can accept it.
We compare JSMin, by Douglas Crockford and Yahoo! YUI
MinifierBytes% of originalgz Bytesgz % original
None428,264100%91,750100%
JSMin249,37258%57,33862%
YUI235,21455%55,99061%
Closure (STANDARD)219,44651%53,51558%
Closure (ADVANCED)166,77439%47,37252%
As you can see, the best by a mile is Closure running in ADVANCED mode.
Real world experience and tips
To get started with Closure checkout the website here http://code.google.com/closure/compiler/ or jump straight in and test out how the compiler will change things in your code by using the online version: http://closure-compiler.appspot.com/
You should be able to use the STANDARD mode with your js without any issues. If you're after the ADVANCED mode though, you're going to need to do a little more work. Firstly, in advanced mode, closure checks what parts of the js are actually used, and which bits can be safely left out. This is useful if you have libraries which you only pick and choose specific parts of. Remember to keep your original js files as this is a one-way trip. If you reference your js code from an html file, you need to tell closure that, by defining some externs. Otherwise it will assume your code isn't used by anything, and remove it! This is done in the following manner:
function init() {
// Some code
}
// Make sure it's extern so that things can access it.
window["init"] = init;
The other thing you need to do is understand how closure treats foo.bar vs foo["bar"].
with foo.bar the bar will be shortened if possible. With foo["bar"] the value bar is left unchanged by the compiler, as it is a string. This means that if you have any external interfaces, such as JSON, you'll need to access that JSON data using ["key"] rather than .key
At first look, this seems counter-intuitive. foo["bar"] is more characters than foo.bar. However, the closure compiler actually changes those foo["bar"] to foo.bar to save space, so everything will be ok :)
The other issue you may come across is externs. If you use external libraries, you need to tell closure about the external functions you're going to be calling, so that it doesn't minify any of those function names. This can be done using an externs file as per their guide. Closure already has an extensive list of externs, which it won't touch. For example, it knows about standard style names. So if you have foo.borderTop = "1px solid #ccc" it will already know to leave 'borderTop' alone. A list can be found here.
This is a little bit of extra work, since you won't see any error if closure has minified something it shouldn't have, but your code won't work. One way to assist you is by asking closure to output a property map list, in which it reports exactly which names it has shortened. You can then look through this, and if you notice something that is for example only in JSON data, or should be an external library reference, you can adjust and compile again. There's also a firebug extension for closure called inspector for better debugging.
The closure compiler is a really good tool in getting your js to the smallest size possible. Saving you and your users bandwidth and cpu. It's worth looking at the issues list for Closure http://code.google.com/p/closure-compiler/issues/list . Of course often, javascript is the least of your worries if you're serving up images, sound files, video etc. But it's good to get as many things optimized as you can. As you can see in the table above though, the worst case (raw js, no gz) compared to the best case (closure advanced, gz) means a reduction to just 11% of the original.
Benefits
So summing up the benefits are of course smaller size and lower bandwidth, should also mean better performance in the browser. One area Mibbit is keen to see how closure can perform is on mobile devices where bandwidth and processor aren't as plentiful as on the desktop. Any small code efficiency gain is good news for mobile where any excessive downloads or processor usage just chew the battery. Minifying in Advanced mode also makes it harder for others to read/steal parts of your code too. So if you're into protecting your code - here's a fair start.
So, look for real world examples like this and try out closure on your code, see the benefits.
If you have any questions or comments on web development in general, we can be found from time to time in http://mibbit.com/#webdev
Mibbit is going to Google i/o, are you? Follow us on Twitter http://twitter.com/mibbit

3 comments:

William said...

Well... round about every blog posts online don't have much originality as I found on yours.. Just keep updating much useful information so that reader like me would come back over and over again.
Dissertation help

Devin Rhode said...

Do you think you could add UglifyJS2 into the comparison? I supports dead code removal now and I bet comes awfully close or supersedes closure advanced compilation

Devin Rhode said...

Do you think you could add UglifyJS2 into the comparison? I supports dead code removal now and I bet comes awfully close or supersedes closure advanced compilation