As my applications have grown in complexity, I’ve followed a path probably quite similar to many of you with respect to .js file maintenance. In the beginning I had one js file to include in the site’s/app’s header, containing just a few basic js functions used across the site.
At some point I became aware of the minifcation trend for JS and CSS files, and began looking at how much bandwidth I could save per page load by doing so. Using an online minifier, I began minifying each .js file after every modification. This became very unmanageable very quickly. I also had to consider the impact of multiple file loads on the browser and how that impacts performance.
I decided to find a way to automate this process. I stumbled upon the JSmin class PHP class, which is an implementation of Douglas Crockford’s JSMin. The solution would implement JSmin, but with a wrapper class that would read each .js file, minify (and compress if possible), and then output into a single file. More helpful ideas were found in this blog article at verens.com.
What I came up with accomplishes the following:
– Given an array of .js filenames, reads and minifies each, writes to a single new file.
– Reads file modification date of each file, if none are newer than the auto-generated output file, the process is skipped.
I’ve encountered a couple of negatives which are easily mitigated. First, in production the process is slow…sometimes 15 seconds. That first user to hit the site after a new js file has been uploaded is going to think the server is down. Remedy this by uploading at off-peak times and immediately surf to the site yourself, saving an unwitting user the 15 second wait. Second, I’ve experienced some kind of funky file collision on occasion which resulted in the minification running on every page load (think 15 second page loads for every page, every time), so when syncing from test to prod I will typically delete the generated file from test first, so prod can then generate its own clean file.
So here’s the script:
And here’s how you would call it in your boostrapping file, etc.
// create array of .js filenames to be minified $scripts = array('jquery', 'jquery.colorbox', 'jquery.livequery', 'jquery.tipsy', 'jquery.validate', 'functions', 'menu', 'childtables', 'datepicker'); // call the fetch static method, supplying the source dir, target dir and the scripts array $scriptfile = App_Minifier::fetch('scripts', 'temp', $scripts); // put the result in a script tag in your html header
Yes I realize that a static class perhaps wasn’t the best choice, but it works and it keeps memory usage to a minimum. I’d probably write it differently today, and may yet refactor it to remove the static.
The output $scriptfile will be a .js filename, generated by hashing the concatenation of all the filenames in the scripts array. This permits different combinations of files to produce different output files, if that’s something you need.
Also note my comment in fetch() about the gzip feature not being used. This caused problems in my particular environment so I’m not using it, but it may work for some of you and I’d be eager to hear from you if it does. To enable, just change line 50 from
$minified = JSMin::minify($contents);
$minified = JSMin::minify($code . $contents);
Oh, and don’t forget to download JSMin.php from github.