JavaScript Packing
Two weeks back I was talking about using JSLint to keep your JavaScript tidy. As I said at the time, the reason I was doing this was so that I could pack the code without too many issues. The tidier the code more likely it will pack well.
By "pack" I mean run it through a process that will remove all the whitespace, comments and (where possible) rename the local variables to use shorter names. Packing can also be known as compressing or "minifying". Basically, it reduces the size of your JavaScript files and hence the time it takes the browser to load them. Faster load time = happier users.
Example
As I mentioned in the post on tidy code the other week, the JavaScript file I'd written ended up being about 3,000 lines and 90kb. Not massive by today's standards, but consider I was writing it for use on mobile devices and you can imagine the issue. Some of the mobile users would be on a GPRS network. Any reduction in file size would offer them a much faster download.
In the end, after looking at the various options available, I managed to get it from ~90kb down to ~50kb. Not bad.
The Easy Option
The easiest way to pack your JavaScript is to use one of the online tools, where you paste your code in to a box, press a button and then copy the returned code. There are two I looked at:
- Packer - Seems very, very fussy. The Base62 encoding seems to offer the best compression, but I just couldn't get the resulting code to work.
- JSMin - Seems to work and with respectable compression results.
In the end though I went with another option.
The Best Option
What I found to be the best option is definitely the YUI Compressor. It's a bit more effort to use, but, while it doesn't necessarily offer the best compression, it is very reliable.
Don't be fooled in to thinking the one that compresses your code the most is the best. Wait until you've pasted the compressed code back in to your app and see if it still works. There's a chance it might not. Some browsers seem fussier than others. For me the target browser was IE Mobile. As you can imagine it was quite fussy!
The YUI Compressor is a Java app, so you need to download and save the Jar file to your PC somewhere. To make it easier to use I renamed the Jar file and put it in a folder with a BAT file I wrote:
The Bat file looks like this:
java -jar yuic.jar --type js --line-break 1000 -o Offline.js Offline_src.js
Should be obvious what it's doing -- it tells Java to run the Jar file in the same folder and passes a set of parameters to it. The parameter following the "-o" is the output files destination and the final parameter passed is the source file of uncompressed JavaScript.
So, all I have to do is paste the code I've been writing in to the *_src.JS file and then double-click the packit.bat file. This then creates (or updates) the Offline.js file with the newly compressed code. I then copy the code from there back to Domino.
Notice the line-break parameter which I've used to tell the compressor to add a new line break every 1000 characters. There used to be a nasty bug (still is?) in Domino Designer where it would crash if you pasted in two much code in to a JavaScript Library that was all on one line. Having been burnt by it a few times I've never dared see if it's been fixed now and still make sure it's split over multiple lines.
Making Development a Little Easier
As you can imagine, having to copy/paste back and forth between files on disk and Script Libraries in Domino can be a bit of a hassle. Especially if you're still in development.
To get round this you can do a couple of things. Firstly, don't start using a compressed version of the code until you're all but done developing. Just before you start final testing, do the compression and test with that instead. Don't test and then compress and expect all to be fine - compression could introduce bugs!
When you do compress you can start using two files in the NSF. Here's the *_src.js file in Domino:
This is where you would carry on doing your development/coding, before passing to the compressor each time. Here's the same compressed version, which would, ultimately, be loaded by the user:
To distinguish between you, the developer, and a user you can add a special URL parameter on (&dev=true) and then in your HTML load either the _src file or the compressed one.
There are lots of different ways of doing it. It's whatever suits you best really. Ideally we'd be able to compress straight from within the NSF. This should be possible with a combination of the Domino Aptana plugin and this plugin from RockStarApps, which should allow YUI compression from the toolbar, although I can't get it to work. Let me know if you do.
Thanks for the tips Jake. Great article!
Even better would be if the packing could be done automagically. Perhaps an agent that runs when the script is changed and makes a packed version? That way, you only have to edit the source version.
Thanks for including the rockstarapps plugin in the write up. I was wondering what you couldn't get to work. Send me an email and I will take a look.
Bob (Buffone)
I used to use Packer almost daily... found that it works great as long as the source maintains strict syntactical compliance. For example, one-line-if statements are fine as long as the curly braces are included. Missing semicolons will also cause it to break. Basically, as you mentioned, if JSLint gives the source a thumbs up, Packer should know what to do with it.
Dojo Shrinksafe, like YUI Compressor, safely compresses unsafe source. It just doesn't reduce the filesize nearly as much as Packer. Of course, the difference won't be noticeable to the end users unless your source was enormous to begin with or they're still on dial-up.
I wrote a batch script (in JScript) to do the following:
- Grab the files using WebDAV from a domino database
- Combine all javascript files (in depedency order) into a single file
- YUICompress the combined file
- GZIP the javascript file
- Upload both the GZIP and non-GZIP javascript file to the domino HTML directory
After a lot of performance testing I found this approach worked best. I am using the ExtJS framework along with a lot of custom code. I got the following reductions:
ExtJS files:
Compressed: 530 KB
Compressed with GZIP: 146KB
TinyMCE (2.13) code with plugins:
Compressed: 235 KB
Compressed with GZIP & GZIP loader: 63KB
Custom Code:
Uncompressed with comments: 840 KB
Compressed: 420 KB
Compressed with GZIP: 108 KB
The GZIP (along with serverside caching) makes a big difference.
I also make use of the YUICompressor and had good experience with it. For GZIPPING i use an Apache Webserver or for local development the puakma web booster.
Here are the results (without optimization):
http://www.handwerker-im-allgaeu.de/hia/web.nsf/gfx/before.jpg/$file/before.jpg
Results (gzipped and YUICompressed):
http://www.handwerker-im-allgaeu.de/hia/web.nsf/gfx/after.jpg/$file/after.jpg
For webprojects, i also get use of CSS Sprite Generator (http://spritegen.website-performance.org/) to minify the http-requests on clientside.
Tip: YUICompressor also works on CSS files !
My batch-file for minify my CSS + JS for www.handwerker-im-allgaeu.de (sorry, german site):
java -jar yuicompressor-2.4.2.jar c:\jsmin\org\jquery.hw.devAS.js -o c:\jsmin\min_yui\jquery.hw.min.js
java -jar yuicompressor-2.4.2.jar c:\jsmin\org\hia.style.devAS.css --type css -v -o c:\jsmin\min_yui\hia.style.min.css
java -jar yuicompressor-2.4.2.jar c:\jsmin\org\hia.style.print.devAS.css --type css -v -o c:\jsmin\min_yui\hia.style.print.min.css
java -jar yuicompressor-2.4.2.jar c:\jsmin\org\jquery.fancybox.devAS.css --type css -v -o c:\jsmin\min_yui\jquery.fancybox.min.css
java -jar yuicompressor-2.4.2.jar c:\jsmin\org\google.maps.devAS.js -o c:\jsmin\min_yui\google.maps.min.js
java -jar yuicompressor-2.4.2.jar c:\jsmin\org\jquery.easing.devAS.js -o c:\jsmin\min_yui\jquery.easing.min.js
java -jar yuicompressor-2.4.2.jar c:\jsmin\org\jquery.fancybox.devAS.js -o c:\jsmin\min_yui\jquery.fancybox.min.js
java -jar yuicompressor-2.4.2.jar c:\jsmin\org\jquery.input.control.devAS.js -o c:\jsmin\min_yui\jquery.input.control.min.js
java -jar yuicompressor-2.4.2.jar c:\jsmin\org\csschart.devAS.css --type css -v -o c:\jsmin\min_yui\csschart.min.css
java -jar yuicompressor-2.4.2.jar c:\jsmin\org\hia_haf_functions.devAS.js -o c:\jsmin\min_yui\hia_haf_functions.min.js
Cheers
Ayhan
I totally agree on JS Min and GZip compression. We send so much Java Script down the wire nowadays.
As some of you might know I have a Domino tool that does JS Minifying and GZip in real time and can cache the result for outstanding performance.
Feel free to give it a test run.
http://www.dominoexperts.com/dapInfo
I tried to install the plugin from RockStarApps (on designer 8.5.1 FP2).
But not working properly.
The file generated is minimized is always zero bytes long (also file.gz)
I do not understand if it is a bug in the designer or the plugin.
Someone did some testing?