4 JavaScript Minifiers Compared
Minification is the act of stripping out unnecessary characters from code to reduce the size, and a minifier is the tool that does it. Most often, the term is applied to JavaScript although the technique can also be used on CSS and (to some extent) HTML.
For the web master, the aim of minification is, of course, to reduce file size and thus speed up transfer times for clients. Using gzip compression offers bigger reductions in file size, and it’s often claimed that this makes minification redundant — a minified, gzipped page isn’t much smaller than an unminified, gzipped page. Although there is some truth in this argument, minification is still a useful technique. And with approximately 10 percent of web traffic passing through browsers that don’t support gzip compression (see http://developer.yahoo.com/performance/rules.html), there is a sizable minority of users for whom minification can help a lot.
The downside with minification is that code becomes difficult to read and modify. One solution is to store your code unminified and then minify it on-the-fly, as clients request it. This is a terribly inefficient way to handle what are usually fairly static resources, though, and definitely not something recommended. Instead, you should keep an unminified copy of the code in a separate directory and pass it through the minifier when you are ready for it to go live, possibly as part of your build process.
What are “unnecessary characters”? In the languages discussed here, whitespace and comments are the main candidates for removal, and many simplistic minifiers remove only these. This is often just scraping the surface of what is possible though — especially with JavaScript.
JAVASCRIPT MINIFICATION
JavaScript offers great potential for minification. Aside from removing whitespaces and comments, Windows-style line breaks (CRLF) can be converted to UNIX-style breaks (LF), and variable names can be shortened.
Let’s look at the typical minification process for a small block of code. In this case, the code handles a function to toggle the “visibility” (more accurately the display) of an element:
function toggle(elementID) {
if ( document.getElementById(elementID).style.display != 'none' ) {
document.getElementById(elementID).style.display = 'none';
}
else {
document.getElementById(elementID).style.display = '';
}
}
As it stands, this function weighs in at 297 bytes.
Before you run it through a minifier, you should attempt some manual optimization. Using a variable holding a reference to the element’s display would be a good start, as shown here:
function toggle(elementID) {
var el = document.getElementById(elementID);
if ( el.style.display != 'none' ) {
el.style.display = 'none';
}
else {
el.style.display = '';
}
}
This takes the weight down to 246 bytes.
You can simplify things a bit more by getting rid of the if/else block and using the ternary operator:
function toggle(elementID) {
var el = document.getElementById(elementID);
( el.style.display != 'none' ) ? el.style.display = 'none' :
el.style.display = '';
}
This takes it down to 193 bytes. So far, you have preserved whitespaces, and the code is still readable.
Now that you’ve seen how to clean up this code, you can pass it through a minifier.
YUI Compressor
One of the most popular minifiers is Yahoo’s YUI Compressor. It’s a command-line minifier, written in Java, that can process both JavaScript and CSS. You can download it from http://developer.yahoo.com/yui/compressor/. (Of course, you must have Java installed.) Running it is simple, as shown here:
$ java -jar /usr/local/bin//yuicompressor-2.3.5/build/yuicompressor-2.3.5.jar
input.js > output.js
Now try it on the sample function introduced earlier:
$ java -jar /usr/local/bin/yuicompressor-2.3.5/build/yuicompressor-2.3.5.jar
function.js > function_minified.js
$ cat function_minified.js
function toggle(a){var b=document.getElementById(a);if(b.style.display!="none")
{b.style.display="none"}else{b.style.display=""}};
A few things have happened here. Unnecessary whitespaces have been removed, and the two variables have had their names shortened: elementID to A, and el to B. Because these variables exist only inside the function, it’s safe to rename them without worrying about it impacting other code.
This takes the function’s size down to 93 bytes — a significant improvement from the original 342.
Just to stress the importance of manually optimizing your code first, look at how the YUI Compressor copes with the original function before you made any changes to it:
function toggle(A){var B=document.getElementById(A);
if(document.getElementById(A).style.display!="none")
{document.getElementById(A).style.display="none"}
else{document.getElementById(A).style.display=""}};
It has still renamed the local variables and removed whitespaces, but the long-winded if/else block with references to the element’s display are still there, and the size is down to only 204 bytes. The YUI Compressor may be clever, but it’s not a mind reader.
You may have wondered why, in the manual optimization examples, var el = document.getElementById(elementID); was not simply written to el = document.getElementById(elementID); to save a few more bytes.
Although it may seem that declaring a variable with var is unnecessary, there is a subtle impact on the variable’s scope. Variables defined inside a function with var are local — that is, they exist only inside the function. Initializing a variable without var causes it to have a global scope, and it is available to code outside the function.
Aside from it making good programming sense to use local variables (because that lessens the potential for variable names to clash), the choice of a local versus global variable also has an impact on minification. For example, say that you run the following through the YUI Compressor:
function toggle(elementID) {
el = document.getElementById(elementID);
(el.style.display != 'none' ) ? el.style.display = 'none' : el.style.display = ";
Following is the output this time:
function toggle(A){el=document.getElementById(A).style.display;
(el!="none")?el="none":el=""};
The YUI Compressor realizes that el is a global variable and shies away touching it in case it breaks another part of your code. In general, it’s best to define your variables with var.
Google Closure
The YUI Compressor is not the only JavaScript minifier out there. The new kid on the block at the moment is Google’s Closure Compiler (http://code.google.com/closure/compiler/), which is set to become the leader of the pack. Crude benchmarking suggests its standard mode offers levels of minification similar to the YUI Compressor, whereas the advanced (and less foolproof) option has the capability to make more savings.
Two of the most exciting features of this advanced mode are function inlining and the removal of unused code.
Inline expansion (or inlining) will be familiar to anyone who has studied C compilers. It’s the act to insert the contents of a function into the place where the function would have been called. This can improve the execution speed (by cutting out the overhead involved in calling the function), and — in the case of small functions that are rarely called — reduce the overall file size.
Let’s look at an example.
function showalert(message) {
el = document.getElementById('alertbox');
el.innerHTML = message;
el.style.visibility = 'visible';
}
x = document.getElementById('formfield');
if (x.value == "no") {
showalert("Did you really mean no?");
}
This is not a useful piece of code, but it serves nicely as an example. Look at the value of a domain object model (DOM) element named formfield. If the value is "no", you call a function to display an alert message.
Let’s see what happens when you run this through Closure. For the sake of readability, let’s use the PRETTY_PRINT formatting option to preserve whitespaces.
java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js
example.js --formatting PRETTY_PRINT
x = document.getElementById("formfield");
if(x.value == "no") {
el = document.getElementById("alertbox");
el.innerHTML = "Did you really mean no?";
el.style.visibility = "visible"
}
;
As you can see, the showalert function has been removed. Its content has been placed inline where the showalert() call previously was.
That’s fine in this simplistic example, where the function is called only once. But what happens if your code makes multiple calls to the function, as shown here?
function showalert(message) {
el = document.getElementById('alertbox');
el.innerHTML = message;
el.style.visibility = 'visible';
}
x = document.getElementById('formfield');
if (x.value == "no") {
showalert("Did you really mean no?");
}
y = document.getElementById('formfield1');
if (y.value == "no") {
showalert("Did you really mean no?");
}
z = document.getElementById('formfield2');
if (z.value == "no") {
showalert("Did you really mean no?");
}
The result is as follows:
java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS
--js example.js --formatting PRETTY_PRINT
function a(b) {
el = document.getElementById("alertbox");
el.innerHTML = b;
el.style.visibility = "visible"
}
x = document.getElementById("formfield");
x.value == "no" && a("Did you really mean no?");
y = document.getElementById("formfield1");
y.value == "no" && a("Did you really mean no?");
z = document.getElementById("formfield2");
z.value == "no" && a("Did you really mean no?");
This time, Closure had the sense not to inline the function.
The second cool feature of the advanced mode — removal of unused functions — is straightforward. If Closure deems that a function will never be called, it removes it.
The danger emerges when the function is called from elsewhere (for example, if you have a bunch of JavaScript files and are passing them through Closure one by one) or is called by means of an eval() statement. eval statements are a common stumbling block for minifiers, are slow to run, and are a potential security problem. So, whenever possible, you should avoid using them anyway. Google also recommends compiling all the code used on a page in one go (by passing multiple filenames to Closure at the command line) to lessen the problem of functions being removed.
Comparison of JavaScript Minifiers
So far, you’ve learned about the two big players, the YUI Compressor and Google Closure. But there are plenty of other JavaScript minifiers out there.
The examples presented thus far have been small, hence the savings have been small, too. To illustrate how useful minification can be, a bigger example is needed.
Prototype (http://www.prototypejs.org/) is a popular JavaScript framework for AJAX developers. Version 1.6.0 consists of a single JavaScript file, weighing in at 122 KB.
Table 4-1 shows the results of passing prototype.js through five of the most popular JavaScript minifiers.
TABLE 4-1: JavaScript Minifier Comparison
| MINIFIER | UNCOMPRESSED (KB) | GZIPPED (KB) |
| None | 122 | 28 |
| YUI Compressor | 71 | 21 |
| JSMin | 91 | 23 |
| Closure (simple) | 70 | 21 |
| Closure (advanced) | 55 | 18 |
| Packer (Perl port) | 90 | 23 |
As you can see, the YUI Compressor and Closure are easily the leaders, and — in the case of the Closure’s simple mode — offer similar levels of compression. If you’re feeling brave, and are willing to debug any errors, Closure’s advanced mode offers an even greater boost.
These results also address the criticism of minification given at the beginning of this chapter — that minification is largely redundant because of gzip compression. The difference in size between the gzipped unminified code and the gzipped YUI Compressor output is 7 KB, a reduction of 25 percent. With Closure’s advanced mode, the decrease in size is more than 30 percent. Coupled with the fact that minified code tends to execute slightly faster, minification of JavaScript certainly should not be ignored.
This article is excerpted from chapter 4 "Keeping the Size Down with Minification" of Wrox's Professional Website Performance: Optimizing the Front-End and Back-End (ISBN: 978-1-1184-8752-5, copyright 2013 John Wiley & Sons) by Peter Smith. Peter G. Smith has been a full-time Linux consultant, web developer, and system administrator, with a particular interest in performance for the past 13 years. Over the years, he has helped a wide range of clients in areas such as front-end performance, load balancing and scalability, and database optimization. Past open source projects include modules for Apache and OSCommerce, a cross-platform IRC client, and contributions to The Linux Documentation Project (TLDP).
Comments
About the Author
I'm the Associate Publisher for Wrox. I work with all of our acquisitions staff who select the authors and topics for our books. Prior to this role, I was an acquisitions editor working mostly on ASP.NET, JavaScript, SharePoint, and a lot of other fun topics. I'm lucky to have worked with some of the best programmer authors in the business. My degrees are in Math (BA and MA) and Physics (BA) and in addition to this blog and my "day job" for Wrox, you'll find me helping as many readers as I can in the p2p.wrox.com forums.


Microsoft "ajax" minifier executed out of the box with no twiking, has actually slightly better results than all the listed options, with the exception of course of Clouse advanced mode.