Serving gzip compressed Scriptaculous and Prototype with ColdFusion

gzip compressed javascript libraries I love Scriptaculous, and mixing it with ColdFusion to create some very nice Rich Internet Applications. But at nearly 300KB, loading Prototype+Scriptaculous is kinda heavy. The workaround for that is shrinking the javascript libraries.

There are a few utilities around the net that will ‘compact’ or ‘shrink’ javascript. Variables are renamed, and all white space is removed – including comments and credits. Not too cool.

But here I’ll show you how to take it a step further and serve javascript compressed with coldFusion. I am able to get Prototype v1601 and Scriptaculous v181 download size down from 288KB to 42KB – with credits intact. ColdFusion 8 is not required – I believe CF5 or better will do (maybe even earlier!). This is a great way to serve gzip compressed content when not being able to control the web server and you don’t have CF8.

  1. Pack/shrink/compact all the javascript files into one. Make sure Prototype is at the top. That work has been done already, easily found on google. That’s how I got mine, it was 148KB. 2:1? Pretty darn good for no compression.
  2. I added credits for each library at the top of that file.
  3. Gzip the file.

So, great. We have a gzip compressed 42KB web 2.0 javascript. Thats almost 7:1 compression – not too shabby.  And with credits intact, thank you very much. Now we have to serve it as such. But you cannot just link to the gz in a javascript src attribute. Most browsers will not know what to do with it. So it has to be served smartly, and correctly. You need the compressed and uncompressed version both handy since older browsers cannot decompress GZ – in case someone tries to surf your site from 1997. And for the compressed version, you need to set the correct content-encoding and content-type headers.

Here is how to do it with ColdFusion. For this demonstration, the files are named:

  • prototype1601scriptaculous181.cfm
  • prototype1601scriptaculous181.js
  • prototype1601scriptaculous181.gz

In your javascript tag, make the src point to the CFM, such as

<script
   src="/includes/js/scriptaculous/prototype1601scriptaculous181.cfm"
   type="text/javascript"
   charset="ISO-8859-1"/>

It’s important that your charset is ISO-8859-1.

This is the contents of prototype1601scriptaculous181.cfm:

<cfif cgi.HTTP_ACCEPT_ENCODING contains "gzip">
<cfheader name="Content-Encoding" value="gzip">
<cfcontent
type="application/x-javascript"
deletefile="no"
file="#expandpath('./prototype1601scriptaculous181.gz')#">
<cfelse>
<cfinclude template="prototype1601scriptaculous181.js">
</cfif>

gzip compressed javascript librariesThis beauty first checks to make sure the browser can handle gzip.

  • If so, it sets the correct Content-Encoding for the file. With cfcontent it sends the compressed data to the browser as type application/x-javascript.
  • If not, it sends the uncompressed js data.

As you can see on the right, the credits are still in the compressed javascript when decompressed by the browser.

In my free time (HA) I’ll create and post PHP, ASP, Ruby, etc version as well. Or if someone else would like to do it I’d gladly post them here.

Other Resources:
http://compressorrater.thruhere.net/
http://shrinksafe.dojotoolkit.org/
http://www.bananascript.com/?home
http://blog.mohanjith.net/2008/03/recipe-for-compressed-scriptaculous.html
http://cfspaghetti.blogspot.com/2007/07/how-to-gzip-compress-coldfusion-8.html

5 Replies to “Serving gzip compressed Scriptaculous and Prototype with ColdFusion”

  1. I hope this comes out OK – here is my PHP version!

    <?php
    // serve it as javascript
    header("Content-Type: application/x-javascript");
    // you don't want it reloading the js every time because the
    // auto generated content always has a new date stamp
    header("Cache-Control: max-age=604800"); 
    header("Last-Modified: Thu, 28 Jan 2010 22:31:25 GMT");
    // get the request header and search for gzip
    $pos = strpos($_SERVER&#91;HTTP_ACCEPT_ENCODING&#93;,"gzip");
    // Careful here - if you do if(strpos()) then it will fail
    // if gzip is the first item in the list (i.e. it's position
    // in the string is zero. Instead we are checking for
    // the failure to make an assignment
    if ($pos === false)
    {
      $js = file_get_contents("./prototype1601scriptaculous181.js");
    }
    else
    {
      header("Content-Encoding: gzip");
      $js = file_get_contents("./prototype1601scriptaculous181.gz");
    }
    echo $js;
    ?>
  2. <?php 
    	// serve it as javascript 
    	header("Content-Type: application/x-javascript"); 
    	
    	// you don't want it reloading the js every time because the 
    	// auto generated content always has a new date stamp 
    	header("Cache-Control: max-age=604800"); 
    	header("Last-Modified: Thu, 28 Jan 2010 22:31:25 GMT"); 
    	
    	// get the request header and search for gzip 
    	$pos = strpos($_SERVER[HTTP_ACCEPT_ENCODING],"gzip"); 
    	// Careful here - if you do if(strpos()) then it will fail 
    	// if gzip is the first item in the list (i.e. it's position 
    	// in the string is zero. Instead we are checking for 
    	// the failure to make an assignment 
    	if ($pos === false) { 
    		$js = file_get_contents("./prototype1601scriptaculous181.js"); 
    	} else 	{ 
    		header("Content-Encoding: gzip");
    		$pos = strpos($_SERVER[HTTP_USER_AGENT],"MSIE 6.0; Windows");
    		if (!($pos === false)) {
    			header("Pragma: "); 
    		}
    		$js = file_get_contents("./prototype1601scriptaculous181.gz"); 
    	} 
    	echo $js; 
    ?>

    That should be up to date! (not tested)

Comments are closed.