Friday, August 17, 2007

Automatically Minimize (Minify) JavaScript

One of the 13 Simple Rules for Speeding Up Your Website is to Minify your JavaScript.

Sidenote: These rules can be easily checked using the YSlow add-on to Firebug.

The recommended tool to minify your JavaScript is JSMin. However, the default use of JSMin is to minimize your JavaScript in a separate step before you deploy your code and then have two JavaScript files - the original JavaScript you use to develop the code and the production "minified" version. For me the problem with that is the fact you have two versions to keep track of and keep in sync. Plus before you deploy your code, you need to make sure all your HTML pages use the minified filename not the original version.

Fortunately, there's a port of JSMin to PHP which allows you minify your JavaScript on the fly, but the usage instructions make it appear that you need to change your script source to point to separate PHP file for each JavaScript, or have a single PHP with all your JavaScript files hard-coded in it -- which is a nice option to get multiple JavaScript files with a single request.

What I'm going to show in this post is how to use jsmin-php to create a filter on your server so that all your JavaScript files are transparently minified as your retrieve them.

First off, download the current version of jsmin-php and save it in your directory. As the current version at the time of this writing is jsmin-1.1.0.php, I'll assume that is the file name.

Next, save the script below as jsmin.php:

<?php
// PHP filter to invoke JSMin on all JavaScript files
// see http://code.google.com/p/jsmin-php/
require_once('jsmin-1.1.0.php');

$js_file = pathinfo($_SERVER['ORIG_PATH_INFO']);
$js_path = substr($js_file['dirname'], 11);
$js_file = $js_file['basename'];

$charset = "utf-8";
$mime = "text/javascript";

header("Content-Type: $mime;charset=$charset");

// Output a minified version of JavaScript file
if (file_exists($js_file)) {
echo JSMin::minify(file_get_contents($js_file));
} else {
echo JSMin::minify(file_get_contents($js_path . '/' . $js_file));
}

?>


Note: If you change the name of this script, you'll probably need to change the 11 on the $js_path definition. That rips the script name (/jsmin.php/) off the beginning of the incoming path on the request so I can use a relative path to find scripts in a subdirectory. It should be the length of the script name plus 2 (for the leading and trailing '/'s).

Now, update your .htaccess file and add the lines:

# make all JavaScript files be minimized via JSMin
AddHandler jsmin .js
Action jsmin /jsmin.php


That should be it! If you fetch a JavaScript file from your server, it should now be minified.


Here are a few quick additions you could add to make YSlow happy.

At the beginning of jsmin.php, adding the line:

ob_start("ob_gzhandler");

should GZIP the output for you.



Also, where the Content-Type header is set, adding the following lines will add an expiration of 49 hours (needs to be > 48 hours to by sufficiently "far future" to make YSlow happy. If you really want to cut it close you could use (60 * 60 * 48) + 1):

$offset = 60 * 60 * 49;
$ExpStr = "Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
header($ExpStr);

4 comments:

Joel said...

Hi, I great work,

I am trying to get it to work. I get errors on not being able to find the scripts. Where do I put the two files?

Magnolia said...

A simple online javascript minifier can be found at http://netspurt.com
It is based on dojo.

rockjock said...

There's an even more lightweight Javascript/CSS minifer for PHP. Follow this link:-

Fat-Free Minify

It's a part of the PHP Fat-Free Framework but you can use it stand-alone. Use is subject to GPL3 terms.

Virendra Dugar said...

Hi,

There are couple of online tools available which can used to minimize the javascript code. Take a look at this link.

http://jquerybyexample.blogspot.com/2011/03/always-minimize-or-minify-your.html

This link has provided 6 different online compressors.

Thanks,
Virendra