Javascript compression filter
Published by peter August 18th, 2006 in ajax, java.Yesterday a colleague asked me whether it is possible to automate compression of javascript code in a web application (the current project has a total of about 150kb of javascript for some of the pages). I decided to look into the issue a bit...
There are tons of offline javascript compressors/obfuscators etc. but the ones using Rhino seem to be among the best. This is mostly due to the fact that Rhino can fully interpret the code and decide whether, for instance, variables are local or not. Another good feature of Rhino is the fact that it is java based. The Dojo toolkit offers a patched version of the Rhino library which can be used safely to compres javascript offline.
I couldn't find inline (filter based) compressors... so I decided to wrap the Dojo Rhino version in a filter. Took some work to figure out how Rhino is used, but I managed to get everything to work.
Instead of pasting code here I decided to install a subversion repository, it is browseable through the web from the following URL:
http://svn.maas-frensch.com/pmutils/javascript_compressor_filter/trunk/
The project contains a minimal webapp demonstrating the use of the filter, a simple build file (be sure to configure your tomcat base-dir for compiling) and can be checked out anonymously.
If you just want to use the filter download the following files and put them in your WEB-INF/lib folder (compiled for java5!):
and add the following lines to your web.xml descriptor:
XML:
<filter> <filter-name>javascript compressor</filter-name> <filter-class>com.finalist.web.filters.JavascriptCompressorFilter</filter-class> </filter> <filter-mapping> <filter-name>javascript compressor</filter-name> <url-pattern>*.js</url-pattern> </filter-mapping>
I've tested the filter on my current, Javascript heavy project and it manages to reduce the filesizes by about 50%.. and they still work! Also it's now safe to fully document 'unwanted' but known behaviour of javascripts without the risk of accidenlty exposing it to external users.
The following example illustrates the working of the filter:
input
JavaScript:
/** * called when the window is finished loading * registers hanlers to each 'anchor' with classname 'button' */ window.onload = function(){ var anchor = document.getElementsByTagName('A'); for(var i in anchor){ if(anchor[i].className == 'button'){ // if A has class button, register event handlers anchor[i].onmouseover = over; anchor[i].onmouseout = out; preload(anchor[i]); // preload images anchor[i].style.backgroundImage = "url('"+anchor[i].getAttribute('out')+"')"; // set default image } } }
output:
JavaScript:
window.onload=function(){ var _1=document.getElementsByTagName("A"); for(var i in _1){ if(_1[i].className=="button"){ _1[i].onmouseover=over; _1[i].onmouseout=out; preload(_1[i]); _1[i].style.backgroundImage="url('"+_1[i].getAttribute("out")+"')"; } } };
After writing the filter I discovered DWR has some java based compression utilities as well; and it is allready on the project classpath. Maybe I'll expand the filter with configuration options for selecting the compressor to use.




















Interesting.
You're suggesting that comments are removed from the compressed output? Could you add that to the example?
I replaced the example, this one should be a bit clearer. As you can see, all comments are stripped and local variables are renamed.... next to the more obvious removal of whitespace.