Comparing Google Closure with UglifyJS

10 July 2011   17 comments   Javascript

Powered by Fusion×

On Kwissle I'm using Google Closure Compiler to minify all Javascript files. It's fine but because it's java and because I'm running this on a struggling EC2 micro instance the CPU goes up to 99% for about 10 seconds when it does the closure compilation. Sucks!

So, I threw UglifyJS into the mix and instead of replacing the Closure compiler I added it so it runs alongside but I obviously only keep one of the outputs.

Here is the log output when I run it on my MacbookPro:

MAKING ./static/js/account.js
UglifyJS took 0.0866 seconds to compress 3066 bytes into 1304 (42.5%)
Closure took 1.2365 seconds to compress 3066 bytes into 1225 (40.0%)
MAKING ./static/js/ext/jquery.cookie.js
UglifyJS took 0.0843 seconds to compress 3655 bytes into 3009 (82.3%)
Closure took 1.3472 seconds to compress 3655 bytes into 4086 (111.8%)
MAKING ./static/js/ext/jquery.tipsy.js
UglifyJS took 0.1029 seconds to compress 7527 bytes into 3581 (47.6%)
Closure took 1.3062 seconds to compress 7527 bytes into 3425 (45.5%)
MAKING ./static/js/maxlength_countdown.js
UglifyJS took 0.082 seconds to compress 1502 bytes into 1033 (68.8%)
Closure took 1.2159 seconds to compress 1502 bytes into 853 (56.8%)
MAKING ./static/js/ext/socket.io-0.6.3.js
UglifyJS took 0.299 seconds to compress 76870 bytes into 30787 (40.1%)
Closure took 2.4817 seconds to compress 76870 bytes into 30628 (39.8%)
MAKING ./static/js/scoreboard.js
UglifyJS took 0.084 seconds to compress 2768 bytes into 1239 (44.8%)
Closure took 1.2512 seconds to compress 2768 bytes into 1167 (42.2%)
MAKING ./static/js/rumbler.js
UglifyJS took 0.0872 seconds to compress 3087 bytes into 1384 (44.8%)
Closure took 1.2587 seconds to compress 3087 bytes into 1235 (40.0%)
MAKING ./static/js/ext/shortcut.js
UglifyJS took 0.0987 seconds to compress 5796 bytes into 2537 (43.8%)
Closure took 1.3231 seconds to compress 5796 bytes into 2410 (41.6%)
MAKING ./static/js/play.js
UglifyJS took 0.1483 seconds to compress 18473 bytes into 10592 (57.3%)
Closure took 1.4497 seconds to compress 18473 bytes into 10703 (57.9%)
MAKING ./static/js/playsound.js
UglifyJS took 0.0824 seconds to compress 1205 bytes into 869 (72.1%)
Closure took 1.2335 seconds to compress 1205 bytes into 873 (72.4%)  

(Note here that for the file ./static/js/ext/jquery.cookie.js Closure failed and when it fails it leaves the code as is and prepends it with a copy about the error from the stdout. that's why it's greater than 100% on that file)

Here are the averages of those numbers:

AVERAGE TIME: (lower is better)
  * UglifyJS: 0.11554 seconds
  * Closure: 1.41037 seconds

AVERAGE REDUCTION: (higher is better)
  * UglifyJS: 45.6% 
  * Closure: 51.5%

(I'm skipping the file that Closure failed to minify)

So, what does that mean in bytes? These are the source Javascript files for two pages but the total is 123949.0 bytes. With Closure that saves me 63833.7 bytes (62 kbytes) whereas UglifyJS only saves me 57760.2 bytes (56 kbytes) of bandwidth.

Discussion...

The fact that Closure fails on one file is a real bummer. I'm not even using the advanced options here.

UglifyJS doesn't save as many bytes as Closure does. This is potentially important because after all, minification process happens only once per revision of the original file but might be served hundreds or millions of times.

Because I run my minifications on-the-fly it does matter to me that UglifyJS is 1220% faster.

It's rare but I have observed twice that the minified Javascript from Closure has actually broken my code. I default to suspect that's my fault for not making the code "minifyable" enough (e.g. too many global variables).

I've just noticed that I'm relying on files that almost never change (e.g. jquery.tipsy.js). I might as well create a ...min.js versions of them and add them to the repository.

In conclusion...

Because of the convenience of UglifyJS being so much faster and that it doesn't choke on that jquery.cookie.js file I'm going switch to UglifyJS for the moment. The remaining bytes that I don't save become insignificant if you add the gzip effect and compared to images the bandwidth total is quite insignificant.

UPDATE (JAN 2016)

I wrote a follow-up post comparing UglifyJS2 with Closure Compiler with the advanced option.

Comments

Anthony Ricaud
Have you tried comparing the minified sizes after gzipping? This is the real metric because we send our code gzipped (right?). That might gives a different result
Peter Bengtsson
Haven't tried yet. Will do when time allows.
Peter Bengtsson
Actually, a quick test:

$ uglifyjs < maxlength_countdown.js > /tmp/uglify.js
$ java -jar ../compiler.jar < maxlength_countdown.js > /tmp/closure.js
$ cd /tmp
$ emacs uglify.js # remove the preamble comment
$ gzip < uglify.js > uglify.js.gz
$ gzip < closure.js > closure.js.gz
$ ls -ltr
-rw-r--r-- 1 peterbe wheel 853 11 Jul 11:23 closure.js
-rw-r--r-- 1 peterbe wheel 857 11 Jul 11:23 uglify.js
-rw-r--r-- 1 peterbe wheel 408 11 Jul 11:24 closure.js.gz
-rw-r--r-- 1 peterbe wheel 405 11 Jul 11:24 uglify.js.gz

So, in this scenario UglifyJS is beaten by 4 bytes but when gzipped it beats Closure by 3 bytes.

Shit this is getting really nitpicky and complex at the same time.
oliver
Closure is also meant to improve runtime (and presumably js load time) performance. Have you tried measuring that? Loadtime is tricky (because you have to try and measure the time between the browser getting the code, and the browser starting execution of that code). Some of the older JS packers can compress JS really well, but killed actual JS load and execution time :-/
Peter Bengtsson
Really?! That's impressive in that case. I didn't know that. I wonder if UglifyJS deals with that at all.
oliver
That was my understanding, but as a caveat I don't use any of these tools (http://nerget.com is not the worlds most heavily visited site :D )
Shashank tyagi
Yes, it does some inlining and other stuff, something compiler does in other languages
John
Can you provide the code (jquery.cookie.js) and the failure and file a bug please (http://closure-compiler.googlecode.com)?
Peter Bengtsson
Done
http://code.google.com/p/closure-compiler/issues/detail?id=513
Thank you for reminding me not to be lazy.
Jeannie
You've got it in one. Couldn't have put it btteer.
Net
Hi,
I'm searching internet for some hours and I simply can't find anything about that Closure Compiler can minify and save every parsed file as separate file.
For example I have structure like this:
js
 |- test1.js
 |- test2.js
 |- test3.js

and I want to minify and save those files to this:
build
 |- test1.min.js
 |- test2.min.js
 |- test3.min.js

Is it possible to declare in Closure options?

Other tasks have such thing. For example in cssmin:
cssmin: {
            minifyCSS: {
                files: [{
                    expand: true,
                    cwd: 'css/',
                    src: ['*.css', '!*.min.css'],
                    dest: 'build/',
                    ext: '.min.css'
                }]
            }
        }
Aner Ben-Artzi
Can you please share specific uglify command you used? I understand --compress and --mangle have several options that can make a big difference. How did you run it?
Peter Bengtsson
Don't remember. It was 2011 :)
jairus
did you enable advanced compilation setting of closure? it would be a lot faster if you turn that on.
Mihail Malostanidis
If you don't enable advanced compilation in closure, you are not even scratching the surface of what it can do, especially for performance but also filesize.
Yes, writing better code and documenting it with JSdocs takes more time than writing a freehand prototype, but anything you plan to maintain (read, everything you plan to use continuously, not a couple of times as an injected script) would strongly benefit from the documentation and type checking of your further additions.
Rodrigo Silveira
Just comparing output size totally misses the point of using Closure in the first place. Besides compressing the output file, Closure also:
 + removes dead code
 + inlines functions and variables when it determines it'd be best to do so
 + type checking

For more information on the entire Closure tools, see https://www.youtube.com/watch?v=M3uWx-fhjUc

Over the years, tools like Webpack and Uglify seem to have made Closure tools less interesting because of all the extra stuff you need to use Closure in advanced mode. I'm curious to see how Uglify and Closure compare today in terms of features, ease of use, and run time performance of compiled code.
Thank you for posting a comment

Your email will never ever be published


Related posts

Previous:
Slides about Kwissle from yesterdays London Python Dojo 08 July 2011
Next:
A taste of the Django on inside Mozilla, Sheriffs Duty 22 July 2011
Related by keywords:
The awesomest way possible to serve your static stuff in Django with Nginx 24 March 2010
Gzip rules the world of optimization, often 09 August 2014
Grymt - because I didn't invent Grunt here 18 April 2014
All my apps are now running on one EC2 server 03 November 2013
HTML whitespace "compression" - don't bother! 11 March 2013
Optimize Plone.org with slimmer.py 15 February 2005
ztar - my wrapper on tar -z 29 June 2005
Goodies from tornado-utils - part 2: tornado_static 22 September 2011
Gzip and Slimmer optimization anecdote 30 January 2007
Comparing jsmin and slimmer 17 September 2009
Launching Kwissle.com 04 June 2011
Slides about Kwissle from yesterdays London Python Dojo 08 July 2011