Force reload of updated CSS and Javascript files with unique filenames

Posted in Apache, HTML and CSS, Javascript and PHP -

When a CSS or Javascript file is changed the visitor's browser needs to get the latest copy of the file to reflect the changes, but it will have been cached and may cause rendering or functionality issues depending on the changes. To force reloading of the CSS and Javascript file the files should be renamed each time they are changed; this can be automated by using PHP to add the timestamp of the file into the filename.

I've posted about doing this previously using the timestamp as part of a query string, but it would appear this method has implications with proxy servers often not caching the files due to the query string. I found that post thanks to the comments to David Walsh's recent post in which he suggests always writing out the timestamp to the Javascript or CSS filename.

The problem with doing that is it will force the browser to always download a copy of those files on every page request which somewhat defeats the purpose of caching. Instead I'll show here how to make the filename unique based on the last time it was modified, and without having to use query strings or rename the file thanks to a little bit of .htaccess magic.

If the stylesheet is css/main.css and the Javascript file js/common.js you can write out the appropriate tags into your page like this:

<link rel="stylesheet" type="text/css" href="/css/main.<?php echo filemtime('/path/to/css/main.css'); ?>.css" />
<script language="javascript" src="/js/common.<?php echo filemtime('/path/to/js/common.js'); ?>.js">
</script>

This will result in filenames in the HTML code like this:

/css/main.1237440708.css
/js/common.1237441675.js

Now we need some rewrite rules in an .htaccess file to rewrite the time stamped version of the filenames to the actual filenames:

RewriteEngine On
RewriteRule ^css/main.[0-9]+.css /css/main.css [L]
RewriteRule ^js/common.[0-9]+.js /js/common.js [L]

Now a request for css/main.[numbers].css will actually result in css/main.css being served.

The above example requires a rule for every stylesheet and Javascript file but we could instead use regular expressions so any CSS or Javascript file with .[numbers]. in it will be rewritten:

RewriteEngine On
RewriteRule ^css/(.*)\.[0-9]+\.css /css/$1.css [L]
RewriteRule ^js/(.*)\.[0-9]+\.js /js/$1.js [L]

And finally, both could be combined into a single rule:

RewriteEngine On
RewriteRule ^(css|js)/(.*)\.[0-9]+\.(.*)$ /$1/$2.$3 [L]

Now you can simply add any additional directory prefix into the first backeted part to apply the rules to those too.



Related posts:


Comments