Sunday, January 31, 2010

Automatic merging and versioning of CSS/JS files with PHP

Introduction

Most sites include a number of CSS and JavaScript files. Whilst developing it's usually easier to manage them as separate files but on a live site it makes sense to merge files to reduce the number of HTTP requests the browser has to make. For JavaScript this is particularly important as browsers block rendering whilst downloading. It's also important to version your files to ensure that browsers download the latest copies when you've made changes.

I hate maintaining this stuff manually so I've written a PHP script which takes care of merging files on the fly whilst also versioning the merged file automatically as the various component files change. The file is merged on first request and cached. Subsequent requests are served the cached version. The script also sets HTTP headers to ensure the user's browser maintains each version in its own local cache therefore preventing repeated requests to the server. Finally an archive of the merged files is maintained to ensure that requests for old versions return the relevant CSS/JavaScript rather than the latest which might not match the user's cached HTML.
Using the script

Step 1: Start by setting the correct mime type for the files you want to merge.

1. define('FILE_TYPE', 'text/javascript');

Step 2: Modify the $aFiles array to include the paths to the files you want to merge. These should be relative to the server document root.

1. $aFiles = array(
2. 'js/yahoo.js',
3. 'js/event.js',
4. 'js/connection.js',
5. 'js/blog-search.js'
6. );

Step 3: Set the location the script should write the archive files to. When first run it will automatically create the folder you specify if it doesn't already exist. For this to work you'll need to make sure that the parent directory, in this case "js", is owned (or is writable) by the user your web server runs as.

1. define('ARCHIVE_FOLDER', 'js/archive');

Step 4: When called directly the script returns the merged code which you reference from your HTML source. For JavaScript files your HTML source should look something like this:

1.

When included via require the script returns the latest version number rather than the source. When rendered it will look like this:

1.

I've used a .htaccess file containing the following mod_rewrite rules to map this filename to the script.

1. RewriteEngine On
2. RewriteBase /
3. RewriteRule js/site_([0-9]+).js js/combine.php?version=$1 [L]

If your host doesn't support .htaccess files you can rewrite your code to:

1.

That's it for the set up. When you make changes to your source files the script will now take care of updating both the code served and the corresponding filename in the HTML source.
Caveats

If you subsequently add files to the script which have older last-modified dates than those already included they won't trigger a new version. I could have added code to support this but it would have significantly increased the complexity of the script. To trigger a new version simply touch or re-save one of the files.
Thanks

No comments:

Post a Comment