Categories
josephscott

Compressed JavaScript


Here is an interesting feature that I didn’t know about, you can compress JavaScript and use that file directly, just like the uncompressed version. So after gzip prototype.js you can use it in a web page with:

<script type="text/javascript" src="prototype.js.gz"></script>

No need for mod_gzip or mod_deflate in Apache. Compress the file once and enjoy the reduced bandwidth and load on your web server.

This is pretty cool because prototype.js (version 1.5.0_rc0) is 55,150 bytes. After gzip on my Mac OS X system prototype.js.gz shrinks down to 12,479 bytes. Easy way to loose 42,671 bytes. You can save another 98 bytes by using gzip -9, down to 12,381 bytes. Unfortunately none of the browsers seem to support bzip, which shrank prototype.js down to 11,556 bytes.

I’ve tested this on Firefox 1.5 and IE 6 on Windows; Firefox 2, Opera 9 and Safari 2.0.3 on Mac OS X. Before you get too excited there is one problem, this doesn’t work on Safari. All of the browsers that I tested showed no difference between gzip and non-gzip JavaScript except for Safari.

So if you want to properly support Safari in your web app you’ll have to skip this idea completely or look at some sort of browser detection mechanism (ick) which would serve uncompressed JavaScript to Safari.

36 replies on “Compressed JavaScript”

joseph i actually made a script that will gzip up the prototype files w/ scriptaculous and cache the gzipped result. It also makes sure that the browser accepts the encoding, and if not will just send them the regular js file. you can download it at http://www.thebusypixel.com/files/prototype_compressed.php.zip

once unzipped and in a public directory you can just use like src=”prototype_compressed.php”.

i got the idea from the tinymce gzip compression, it seems to work pretty good. i use Pear’s Cache Lite to do the caching, but its so few lines of code you should be able to adjust it pretty easily.

I’m pretty sure Safari does support compressed http responses, but only when the server tells the client that it’s compressed. This is how it’s supposed to work:


Content-Type: text/html
Expires: Fri, 21 Jul 2006 21:49:54 GMT
Content-Encoding: gzip

But here’s what happens when you just zip the file and point directly to it:


Content-Type: application/x-gzip
Expires: Fri, 21 Jul 2006 21:49:54 GMT

Safari is doing it right. The server said “this is not html”, and IE says “wow, an html file! lemme unzip it!”. Firefox does the same because they want to be compatible.

But it’s dumb luck. Who knows if it will break Konquerer, Opera, and virtually any mobile browser? I agree it’s a nice hack if you don’t have mod_gzip on your host, but treat it as such: browser detection for the clients that you know implement this behavior.

I can’t get this to work on my apache 2.x servers with firefox and IE. What’s the trick? Both browsers fail to detect that the content is compressed and try to parse the raw gzipped data.

I tried mucking with the AddType settings in Apache, but no luck. Any ideas?

sorry here again:
at the to of javascript:
php
ob_start (“ob_gzhandler”);
header(“Content-type: text/javascript; charset: UTF-8”);
header(“Content-Encoding: gzip”);
header(“Cache-Control: must-revalidate”);
$offset = 60 * 60 ;
$ExpStr = “Expires: ” .
gmdate(“D, d M Y H:i:s”,
time() + $offset) . ” GMT”;
header($ExpStr);
?>

You can do even better than that!

Take a look at the javascript compression from

http://dojotoolkit.org/docs/compressor_system.html

This removes javascript comments and renames variables and seems pretty
reliable and effective.

So for prototype.js, you can go from 28376 bytes (original file) to 19632 bytes (comments stripped, variables renamed) which then (gzip) compresses to 5794 bytes. If you compress the original file, you get 6581 bytes. So you save 1 KB.

With larger javascript files, it can get better:

See http://lists.rubyonrails.org/pipermail/rails/2006-August/060553.html

Stephan

You can use .htaccess.
Save a compressed javascript file as *.jgz, and write .htaccess like this.

[.htaccess]
=========================
RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} “.*Safari.*” [OR]
RewriteCond %{HTTP:Accept-Encoding} !gzip
RewriteRule (.*).jgz$ $1.js [L]

AddType “text/javascript;charset=UTF-8” .jgz
AddEncoding gzip .jgz
=========================

Why don’t you just enable server compression? The browser reports if it accepts compressed data, and the server will automatically compress it before transport. That way you don’t even need to bother with zipping your javascript.

Late reply but this article is tagged in Stumble Upon.

Doing this should be entirely useless. This is what your web server should do, and do correctly. If you actually look at the headers from any JavaScript/CSS file, you will likely see that it is already compressed with gzip.

Also, gzipping on the fly with PHP is useless, too, for a static file. Apache (and others) will gzip the file and keep it cached in memory. If you gzip it on every single request (as ‘silence’ did above), you are making the server recalculate the compression EVERY request. His script is awful, too. It attempts to set cache directives but doesn’t actually check incoming cache headers — a browser with that script will redownload the entire file every single request!

dae is right. all you should do is to put “SetOutputFilter DEFLATE” into .htaccess file in yout JS directory. you don’t have to do anything more than this (don’t compress your files! apache/mod_deflate will do it for you). mod_deflate must be enabled of course.

Here is what I came up with for an .htaccess file. Rather than calling a .jgz or .js.gz file from your HTML, you stick with calling file.js and let apache determine what file it needs to send. mod_rewrite then checks to make sure you don’t have safari, you support gzip, and that the precompressed static file.js.gz exists, and if all goes well, it sends the precompressed file. It has worked well for me and degrades nicely since we don’t have to check for safari when sending the html. Paired with some expire headers, etc, this should work nicely in reducing load times.

ForceType text/javascript
Header set Content-Encoding: gzip

RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} !”.*Safari.*”
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule (.*).js$ $1.js.gz [L]
ForceType text/javascript

Apparently there is no preview for comments, so hopefully tis will show the filesmatch tages for the .htaccess files…

<FilesMatch “.js.gz$”>
ForceType text/javascript
Header set Content-Encoding: gzip
</FilesMatch>
<FilesMatch “.js$”>
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} !”.*Safari.*”
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule (.*).js$ $1.js.gz [L]
ForceType text/javascript
</FilesMatch>

Just in case anyone happens to land here having to deal with the same webhosting restrictions as I do: smilkobuta’s solution is the safest bet.

I’m on a (major) host that doesn’t support ForceType nor SetOutputFilter. So I went for smilkobuta’s .jgz thing. It does force you to gzip every file manually plus you need to call file.jgz instead of file.js files from your HTML, but nevertheless it works, it’s fast, it doesn’t eat up resources and it won’t send the gzipped file to a non-supporting browser. I was able to compress my prototype.js and sifr.js files to around 50% sizes.

Oh and please note that the posting engine here breaks the code: whenever there is a ” (quote), it’s automatically changed into unicode, which WON’T WORK in the .htaccess file. You will have to re-type the quotes manually.

Can someone please explain what advantage this approach has over using gzip/deflate in apache?

In apache too, you can pre-compress and keep the .gz version in addition to unzipped version. And apache will decide whom to serve what depending upon your rules and incoming headers.

Thanks,
OPM

Omprakash, the only advantage is that the above works even on hostings that don’t support mod_deflate nor mod_gzip, which happens to be pretty usual.

If you can use SetOutputFilter in you .htaccess or apache conf file, you don’t need this at all. Happy deflating!

Cheers,
Filip

There is some small advantage in using precompressed JS files as well since apache doesn’t have to compress it on every request. Of course if you are using mod_gzip, it supports static compressed files, but I don’t believe mod_deflate does.

Wing

Hi,

why compress on your own?

Use pack:tag, this is JSP Taglib that automatically minifes resources (JS and CSS) transparently, caches them and servers them from memory or saves them to file, that would be served instead. Give it a try:

http://packtag.sf.net

Daniel

There is a “feature” style bug in CFNetwork, which safari uses to download files like javascript, html, and so on. The short version is that it tries to force safari to download any url where the URL contains “.gz”, and that if such a url is referenced, like from a script tag, inside a html document, instead of decompressing it, it just doesn’t. The javascript parser then tries to read the raw gzip binary, fails, and doom soon follows!

The work around is to simply not leave .gz in the filename. I call my compressed javascripts .jsgz and have the needed code in my .htaccess to tell apache that .jsgz files have the encoding of ‘x-gzip’, and the mime type of ‘text/javascript’. It works great. The bug has been reported to apple and members of the WebKit team are pushing for it to be fixed soon, but till then this workaround works and brings you the support of all the major browsers!

The only problem I see with the suggested methods is that most rely on having the possibility to use .htaccess, a thing I cannot do on one hosting service I use… The solution more interesting for me was the first one proposed byKenrick, because it use a .php script but unfortunately the link to the script doesn’t work anymore… 🙁

For those of you who can’t get this to work here is some more detailed information.

.htaccess
RewriteEngine On
AddEncoding x-gzip .gz
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{HTTP_USER_AGENT} !Safari
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule ^(.*)$ $1.gz [QSA,L]

This one will work on css and js files any file really, just gzip it and if it exists it will use it (unless the client is using safari).

To make this work you have to fix the mime records that apache uses. In httpd.conf comment the global setting that looks like this:

#AddType application/x-tar .tgz

Then you need to make sure that your “AddEncoding x-gzip .gz” directive will work by setting your directory to have “AllowOverride All”. Still in httpd.conf in my vhost I added:

<Directory /home/username/public_html>
AllowOverride All
</Directory>

If there are still problems edit mime.type and comment out the gzip line. Don’t forget to restart apache. I hope this saves someone hours.

Hey,

Do you guys think there is a performance hit by using mod_gzip instead of this technique? Would pre-compression give any long-lasting performance improvements?

Or do you guys think that with the caching in mod_gzip it becomes irrelevant for static files like JS anyway because the server will only zip the first time and not onwards?

Your comments pls

Leave a Reply

Your email address will not be published. Required fields are marked *