Rule 3 of Steve Souders’ YSlow suggests that websites should Add a far future Expires header to the components. Components with a cache header could be static files such as those with extensions .css, .js, .jpg, .png, .gif etc. This gives a huge boost in client side performance of users with a primed cache. In apache this is done via mod_expires and an example configuration would be:
ExpiresActive On
ExpiresByType image/x-icon "access plus 1 month"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
All this works well until you need to update a cached static file. The users with the primed cache will either have to wait 1 month to get the new file, or explicitly invalidate their cache. Some people will even ask their users to do a hard refresh but this obviously does not scale and it’s not very robust.
Since you cannot send an automatic signal to the browsers to reload those files all you can do is change the URL of those files (explicit invalidation). You could simply rename all those files, but an easier way to achieve the same effect is by adding a fake (unused – dummy) parameter at the end of the resource URL:
<img src="logo.jpg?2" />
The next logical step would be to automate this into the build system and have every production release feature new cache killer tokens. It seems that many well known sites do that already:
href="//s.fsdn.com/sd/idlecore-tidied.css?T_2_5_0_254a"
src="//s.fsdn.com/sd/all-minified.js?T_2_5_0_254a"
href="/content/all.css?v=3184"
src="/content/js/master.js?v=3141"
@import "/css/189/global.css";
src="http://media.digg.com/js/loader/187/dialog|digg|shouts"
@import 'http://wwwimg.bbc.co.uk/home/release-29-7/style/homepage.min.css';
src="http://wwwimg.bbc.co.uk/home/release-29-7/script/glow.homepage.compressed.js"
href="http://static.guim.co.uk/static/73484/common/styles/wide/ie.css"
src="http://static.guim.co.uk/static/73484/common/scripts/gu.js"
What happens with images referenced from within css files? You could rewrite the css files automatically as part of your production build process with Ant.
<tstamp>
<format property="cacheKill" pattern="yyyyMMddhhmm" locale="en,UK"/>
</tstamp>
<target name="rewrite-css">
<replace dir="${build.web.dir}" value="css?${cacheKill}")"><include name="css/**/*.css"/><include name="scripts/**/*.css"/><replacetoken>css")</replacetoken></replace>
<replace dir="${build.web.dir}" value="png?${cacheKill}")"><include name="css/**/*.css"/><include name="scripts/**/*.css"/><replacetoken>png")</replacetoken></replace>
<replace dir="${build.web.dir}" value="gif?${cacheKill}")"><include name="css/**/*.css"/><include name="scripts/**/*.css"/><replacetoken>gif")</replacetoken></replace>
<replace dir="${build.web.dir}" value="jpg?${cacheKill}")"><include name="css/**/*.css"/><include name="scripts/**/*.css"/><replacetoken>jpg")</replacetoken></replace>
<replace dir="${build.web.dir}" value="css?${cacheKill}')"><include name="css/**/*.css"/><include name="scripts/**/*.css"/><replacetoken>css')</replacetoken></replace>
<replace dir="${build.web.dir}" value="png?${cacheKill}')"><include name="css/**/*.css"/><include name="scripts/**/*.css"/><replacetoken>png')</replacetoken></replace>
<replace dir="${build.web.dir}" value="gif?${cacheKill}')"><include name="css/**/*.css"/><include name="scripts/**/*.css"/><replacetoken>gif')</replacetoken></replace>
<replace dir="${build.web.dir}" value="jpg?${cacheKill}')"><include name="css/**/*.css"/><include name="scripts/**/*.css"/><replacetoken>jpg')</replacetoken></replace>
<replace dir="${build.web.dir}" value="css?${cacheKill})"><include name="css/**/*.css"/><include name="scripts/**/*.css"/><replacetoken>css)</replacetoken></replace>
<replace dir="${build.web.dir}" value="png?${cacheKill})"><include name="css/**/*.css"/><include name="scripts/**/*.css"/><replacetoken>png)</replacetoken></replace>
<replace dir="${build.web.dir}" value="gif?${cacheKill})"><include name="css/**/*.css"/><include name="scripts/**/*.css"/><replacetoken>gif)</replacetoken></replace>
<replace dir="${build.web.dir}" value="jpg?${cacheKill})"><include name="css/**/*.css"/><include name="scripts/**/*.css"/><replacetoken>jpg)</replacetoken></replace>
</target>
This will take care of the following background image reference styles for css, png, gif and jpg files:
... background-image: url("images/ed-bg.gif");
... background-image: url('images/ed-bg.gif');
... background-image: url(images/ed-bg.gif);
and convert them to:
... background-image: url("images/ed-bg.gif?200905031126");
... background-image: url('images/ed-bg.gif?200905031126');
... background-image: url(images/ed-bg.gif?200905031126);
Good luck!