Reducing Bandwidth Usage when Deploying Web Applications


by serving your JavaScript source code files as one big gzipped file. Nowadays when we’re getting more and more nice applications (and widgets, gadgets, mashups, and whatnots) running on the web, there’s a lot of talk about user experience and stuff, which involves the whole experience of using a web site. Good content, design, and fancy programming, of course make up the core of a good user experience. But we all wants sites to be quick and responsive to load too, right?

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:

  1. Make apache serve .gz.js files with gzip transfer encoding
  2. Bundle up all your JavaScript files into one (or a few) big file(s)
  3. 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
Gzip transfer encoding is great! The only bad thing about it is that on dynamic content, the web server will have to use up some processing power to compress the files on the fly, but in this case, we’re serving static JavaScript source files, so that’s not even an argument! (As for the client, if it’s got enough CPU to run your web app, it’s not gonna have any trouble doing a little unzipping…)

The easiest way to do this is to edit the .htaccess config file in the directory where you put your JavaScript files, or any directory above that one to make it more global. The only thing you have to do is add the following line:
AddEncoding x-gzip gz

This adds the gzip transfer encoding to apache for files with a “gz” file extension.

Notice the title says “.gz.js” though: by adding “.js” at the end, the files will be served correctly with the text/javascript mime type. Otherwise the browser might go berserk. That’s also why I wouldn’t recommend using “.js.gz”; it’ll get served with gzip transfer encoding alright, but not with the JavaScript mimetype.

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.

2. Bundle up your JavaScript source file into one (or a few) big file(s)
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.

Another good way to do it is using Dojo ShrinkSafe. ShrinkSafe will not only append all your source files into one big file, but also reduce the size even further by optimizing the JavaScript code. However, I have had problems with scripts not running correctly (in all browsers) after running them through ShrinkSafe, despite their claims of it being “safe”. I would especially recommend not using the “strip newline chars?” option. Anyway, the file size reduction the results from using ShrinkSafe is small compared to just gzipping the files (I’ll show you some numbers later) so if you’re afraid of regressions, don’t use it.

3. Gzip your One Big File(s)
Now that you’ve got one or two or so JavaScript files, you need to gzip them into a gzip file. You can use the command-line gzip tool on the server to do this, like:
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:
<script type=”text/javascript” src=”scriptfile.gz.js”></script>
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):

Original
libs.js: 95 kB + 3 kB + 38 kB = 135 kB
minesweeper.js: 3 + 9 + 9 + 4 + 2 = 25 kB

Shrunk
libs.js: 92 kB (32% smaller)
minesweeper.js: 13 kB (48% smaller)

Gzipped
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.

Bookmark and Share

One Response to “Reducing Bandwidth Usage when Deploying Web Applications”

  1. Anonymous says:

    You mix up things a bit in the compression section. You need to distinguish between Content-Encoding/Accept-Encoding and Transfer-Encoding/TE.
    What you are showing is setting a specific Content-Encoding.

    Please fix it, its confusing ;-)

Leave a Reply

Code*: