Wednesday, March 5, 2008

Gzipping/serving gzipped static content (JS/CSS)

Bandwidth is still a concern for a big part of the web users. To save bandwidth, the simplest job is to compress the content that "never" changes. For instance JS-frameworks.

There are a couple of approaches to this, "packing" utilities like Dean Edward's packer. This compresses the JS in such a way that it's still "compilable" in it's raw form. Another way is to gzip the file. This requires that the browser unpacks the file before it is sendt to the JS "compiler".

I prefer to use both packed and gzipped JS frameworks in production. This guide will hopefully help you serve gzipped JS-files without too much hassle.

The JS-lib I use in the accompanying demo, MooTools is 72KB "unzipped" (the version that is packed using JsMin). Gzipped, it's just shy of 20KB.

Preparing the Domino server

To enable gzipped content on the server, create a web site rule (requires restart of the HTTP-task).

Example of rule:

The above rule works like this: For all files in a subfolder named gz, the domino-server will add a HTTP-header, Content-Encoding, with the value of gzip. This tells the browser that the content it is downloading is compressed.

At Compendia, where I currently work, we've set this as a global rule, as it doesn't affect any other content.

Compressing files

To compress files on your machine, you need an application that can gzip files. I use gzip for DOS.

Download gzip for DOS:
32-bit (doesn't work on 64-bit Vista)

Extract the downloaded utility to a folder of your choice. At work, I have it on c:\gzip.

Copy the file(s) you want to compress into the folder you extracted the gzip-utility.
Open command-line. cd into the folder you've extracted the gzipping-utility.

For the 64-bit utility: minigz64 name_of_file.js
For the 32-bit utility: gzip name_of_file.js

Be aware of that the dos application overwrites the original file by default.

Adding the files to a DB

Add the uncompressed/compressed file (New File Resource) to the DB of your choice. Rename the uncompressed file to lib\[filename].js, and the compressed to gz\[filename].js

With the aforementioned web site rule in place, browsers opening the gzipped file will get the correct HTTP-header, indicating gzipped content.

What about users that doesn't have gzip-enabled browsers/etc?

Some proxies/browsers/thin clients doesn't support/allow gzipped content. It's easy to identify if a browser supports gzipped content:

supportsGzip := ( @Contains( @GetHTTPHeader( "Accept-Encoding" ) ; "gzip" ) );

In the index-page of the simple demo-app, I compute the folder in a script-tag by the presence of Accept-Encoding: gzip header.

"<script src=\"/" + @WebDbName + "/" +
@If( supportsGzip ; "gz" ; "lib" ) + "/mootools-release-1.11.js\"></script>"

>> Download demo-app with gzip for Dos/mootools compressed/uncompressed.

PS! The index-page needs to run on a server with gzipping enabled, like in the picture at the top of this post. Either that, or you can run the browser in HTTP 1.0-mode. HTTP 1.0 doesn't have the Accept-Encoding header.

Good luck!


efreitasrj said...

That's exactly the same process we use at my company to serve gzipped content. The only difference is that we don´t use packer any more.

If you compress a large and complex library like Ext using packer, the browser has to decompress the file using a javascript algorithm, which can impact overall performance.

Gzipped content is decompressed natively in C code, which is much faster, and considering that packing a content that will be gzipped gives only a marginal reduction in file size, the increased decompression time (which sometimes amounts to a couple of seconds) if a bad trade-off, in my opinion.

The only case in which packer might come in handy is if you are serving non-gzipped content to HTTP 1.0 browsers, as you mentioned.

Tommy Valand said...

I'm not sure how good/bad John Resig's benchmark is, but according to his test of evaluation of jQuery, the fastest way to deliver JS to the browser is to minify and gzip.

Compression Time Avg
minified 519.7214
packed 591.6636
normal 645.4818

If one follows his recommendations. Always minify, gzip when possible, avoid packing.

Thanks for the comment by the way, it forced me to do a little research :)

Joost said...

Thanks for your blog.I fllowed your information and used your demo nsf.The index Page displayed "Your browser supports gzipped content!",but always alert a message"invalid charater" on line 1.Would you like to help me?

Tommy Valand said...

The error implies that the Content-Encoding-header isn't being sendt.
Did you set the rule as a global rule, or for a specific domain?

On one of the servers at work, we have to set the rule per domain. I'm no admin, so I don't know the reason why.