Special thanks to our guest blogger, Dan Hardiker from Adaptavist.
Confluence in its naked, default form is nice, fast and responsive from the user’s perspective – but load it up with a few too many plugins and a nice looking theme, and you can soon find yourself waiting eight to ten seconds for a page to load.
The great developers at Yahoo! recently released YSlow, which works as a bolt-on for FireBug. This plugin analyses a webpage and compares the results to a set of performance enhancing rules that Yahoo recommends.
Now, there are a few of the rules (most notable the CDN rule) which aren’t applicable to most Confluence sites, but there is one I would like to focus on which does make a big difference: the expiry rule.
“But what if I upload a new version of the plugin, and the file has changed?” I hear you cry! “The browser will never ask for my new file!” Fear not, because the technique of making the browser play dumb and assume that a static resource URL hasn’t changed puts the control back into your hands. All you have to do is change the URL when your plugin is updated. The browser will see a new URL, think it’s a totally new resource, and then cache it in the same long-lived manner. The next time you update, change the URL again and repeat the process.
For example, in my plugin I have a library.js file which I would traditionally have served using /download/resources/my.plugin.key:any-module-key/resources/library.js. This would have had a corresponding <resource/> module in my atlassian-plugin.xml file. The response headers for this file when served up through the standalone environment are set to:
What we want is to change it so that I’m actually pulling from /download/resources/my.plugin.key:any-module-key/HASH-GOES-HERE/resources/library.js, with the Cache-Control header set to a large max-age and set to private, and with the Expires header set to 10 years in the future or so. That hash just has to be unique, and I usually prefer to use the date and time (to the minute) that the plugin was enabled. This way, the hash changes automatically when the resource is likely to have changed, and remains the same (leaving the browser to safely assume that the files haven’t changed) when not.
There are three options for improving on the current caching situation:
- Change the <resource/> plugin module so that it allows this sort of thing transparently, perhaps configurably (so the hash can be set to change per module reload, plugin reload, Confluence restart or in fact never). This fix is not likely to appear immediately, and would require an upgrade of each Confluence system to reap the benefits.
- Add in your own cache header modifying servlet which looks at the pluginAccessor to get the information it needs to create the hash (a static variable is likely to work too). This requires a fair amount of implementation effort and would need to be duplicated in each plugin you want the effect to apply to.
- Use WebResourceManager! It already does it!
Yes – in the years that I have been using Confluence, at some point a funky caching filter has been added and I completely missed it!
If you have a macro or action that is being rendered by velocity, just change
If you aren’t using a macro or action (e.g. if you are outputting from a servlet plugin module) then you could alternatively, of course, get hold of the WebResourceManager component and call the method yourself.
When using the WebResourceManager you’ll find the script location changes to something like /s/808/1/1.0/_/download/resources/my.plugin.key:any-module-key/resources/library.js with the following headers:
Excellent! I’m off to go hunt down some of my plugins with large resources (like the Advanced Search Plugin, and the Atlassian Plugin Repository Client) and instantly make them faster to use.
I would highly recommend that you do too.
Architect & Developer