Highly Opinionated Thoughts on Programming

by Elnur Abdurrakhimov

Assets Cache Busting in Symfony

Jun 7, 2014

When using Assetic or the asset function to output assets in Symfony, you get something like the following in the HTML output:

<link href="/css/style.css" rel="stylesheet"/>

Unless you disable caching on the web server level, this CSS file will get cached the first time it’s retrieved. Even if you change the file, the cached version will still be used. This leads to a problem called “works on my machine” because the developers will be getting the latest assets while some clients will be getting older cached assets.

To solve this problem, there’s a technique called cache busting and one of the ways to implement it is to append some unique value to the path when the file has changed, like so:

<link href="/css/style.css?1234567" rel="stylesheet"/>

Symfony supports this strategy with the assets_version parameter that you can assign a value to that will be appended to all assets paths automatically. For the example I’ve given above, this is how you could achieve that:

1 framework:
2     templating:
3         assets_version: 1234567

Now, every asset path output by Assetic or the asset function will be appended with ?1234567.

Automating Cache Busting With Capifony

Since updating the assets version each time you update an asset is manual and therefore prone to be forgotten to be done, I’ve came up with a solution to update the assets version each time I deploy an application with Capifony.

To do that, we should first replace the hardcoded version with a parameter and put it into parameters.yml:

1 parameters:
2     assets_version: 1

Now let’s use the parameter in configuration in config.yml:

1 framework:
2     templating:
3         assets_version: "%assets_version%"

What left is to update the parameter each time we deploy. To do that I add the following code to deploy.rb:

1 before "deploy:finalize_update" do
2   capifony_pretty_print "--> Update assets version"
3   run "if [ -f #{shared_path}/app/config/parameters.yml ]; then sed -i.bak 's/\\(assets_version:[[:space:]]*\\)[[:digit:]]*/\\1#{release_name}/' #{shared_path}/app/config/parameters.yml; fi"
4   capifony_puts_ok
5 end

It backs up the current parameters.yml file by copying it to parameters.yml.bak, finds the assets_version parameter and changes its value to the timestamp of the deploy. This results in parameters.yml look like the following:

1 parameters:
2     assets_version: 20140606222249

And the generated asset path like this:

<link href="/css/style.css?20140606222249" rel="stylesheet"/>

© Elnur Abdurrakhimov