This trick is so simple and incredibly easy to pull off that you have no reason not to do it. There are essentially three things involved:
- Make apache serve .gz.js files with gzip transfer encoding
- Gzip your One Big File(s)
Let’s go through these step by step…
1. Make apache serve .gz.js files with gzip transfer encoding
AddEncoding x-gzip gz
This adds the gzip transfer encoding to apache for files with a “gz” file extension.
This solution works even with clients that don’t support the gzip transfer encoding, because web browsers send an “accept-encoding” header that tells the server which encodings the client supports, so apache won’t use gzip transfer encoding if it’s not supported by the client.
This means simply appending all your source files to one file. Or a few files. I usually bundle up the libraries/utility code etc, i.e. code that you don’t change very often, into one file and the rest of the app into one file that gets updated more often. You can do this by copy-pasting in your text editor if you like, or make a script that does it. I usually have the whole deployment process automated on the server, which I’ll write about some other time perhaps.
3. Gzip your One Big File(s)
gzip -n9c scriptfile.js > scriptfile.gz.js
The -n option means to not store the the original file name in the gzip file. No big deal if you do, but there’s no reason to do it either. -9 means maximum compression. I like doing things to the extreme! And -c means to write to standard output instead of modifying the source file, so we need to pipe it “>” to a .gz.js file at the end. Or you can use a UI tool such as 7-Zip that supports gzip compression. That’s just damn easy.
Then upload the .gz.js script file to your server, and change all your old <script> tags for every file you had to one pointing to it. I.e. like:
That’s all there is to it!
Show Me The Numbers!
Let’s use my Minesweeper game for comparison. The code is served in two files: libs.gz.js containing Prototype and Scriptaculous core and Effects libraries, and minesweeper.gz.js containing the actual game. The breakdown of the files in these libraries before combining them is as follows (at the time of writing):
libs.js: 95 kB + 3 kB + 38 kB = 135 kB
minesweeper.js: 3 + 9 + 9 + 4 + 2 = 25 kB
libs.js: 92 kB (32% smaller)
minesweeper.js: 13 kB (48% smaller)
libs.js: 30 kB (78% smaller)
minesweeper.js: 7 kB (72% smaller)
Shrunk + gzipped
libs.js: 27 kB (80% smaller)
minesweeper.js: 4 kB (84% smaller)
Now, add to that the fact that every HTTP request for a file incurs a 1 kB overhead in HTTP headers, and you get an original total amount transferred of 135 + 25 + 8 = 168 kB compared to 27 + 4 + 2 = 33 kB, i.e. a total saving of 135 kB, i.e. 80% less bandwidth used, not to mention that making two http requests is much faster than making eight http requests!
The next step would be to bundle up html, css, scripts, and everything you possibly can into one request… (In fact, I have scripts doing that automatically at runtime on some sites…) But you have to draw the line somewhere. There’s a definite trade off in maintainability, cachability, and compatibility of the site. So I’ll stop here.