Although Magento 2 already addresses this pretty well, proper handling of static assets when using a full page cache with Magento 1 is not something I have yet seen advice addressing. This post attempts to provide a good working method to allow you to both update your static assets, but also keep your full page cache intact.
Consider the following. You have your Magento store up and running, and have also implemented a full page cache. This of course means that the URL's to all of the static assets for each page are also cached with the page HTML. This in turn means that as soon as you add or remove a JS file, the full page cache for the affected pages becomes out of date because it doesn't contain the changes to static assets as this newly added or removed URL is not reflected in the cached HTML. This is the case both with merging enabled or disabled. When disabled each static asset on the page has it's own URL, and when it is enabled the URL for each merged asset is created by generating a hash of all of the files which have been combined to create the merged file. In this case when you add or remove a CSS or JS asset, the resulting hashed file name for the merged asset changes, but this is of course not reflected in your cached page HTML. So when a customer views an affected page, at best they will be served an outdated CSS/JS file without the latest file changes just made, or in the case of the merged CSS/JS cache being cleared, will be served an invalid URL pointing to a merged file which no longer exists. The result of this is that the page will render without any CSS/JS functionality.
So that's the scenario we need to address. There are really two things to consider when thinking about a solution. The first is browser caching, and the second is the fact that because we are using a full page cache we don't want to have to change the page HTML when adding or removing CSS and JS assets.
A common approach is to implement some kind of file name change when altering static assets. This is great to address the first consideration as there is no way the browser can use it's own cached content as it's a new file. However this approach really doesn't work along side full page caching as changing a file name of course means you have to refresh the cached content so that the new asset changes are reflected.
We need a solution that combines the best of both worlds. Intelligent browser caching of static assets, combined with no change of a pages HTML. The solution requires changes to both the stores code and the webserver. On the webserver we need to add headers for JS and CSS files to tell the browser it can use these assets cached, but it must check they do not need updating first. We can do this with the addition of a simple Cache-Control: no-cache header for these file types. By adding this header the browser is instructed (despite what no-cache may sound like, the no-store directive means the browser cannot cache the file) that it can use it's cached versions of these files but it must check with the server for a more recent version of the file before it does.
Implementing this header means that we can use the same file names for serving CSS and JS assets, and while they are unmodified the user will get the performance benefit of this, but as soon as we update the content of any of these files the browser will get the new copy. This means that the user will always see the latest styling and functionality, but still have the performance benefit of browser caching.
Great, but what about addressing the scenario above? This still doesn't help with maintaining the full page cached content the addition/substraction of CSS or JS will require a change in the affected pages cache as the HTML will need to be updated. Well Magento gives us a partial solution with merging. To greatly reduce the number of requests per page we highly recommend you always have this enabled in a production environment anyway, so we will take merging being enabled as starting point here. I know there are arguments both for and against enabling merging, but the benefits really do far outweigh the negatives in our opinion (if you want to read more about this have a look at this post on speeding up Magento).
As discussed above, Magento creates merged CSS and JS file names by creating a hash of the files included in that merge. Great if we don't mind the page source code changing, but here we do so the solution is to not have the names of these merged files change even when adding or removing assets from the merge. Well that's exactly what we've done and we have included these changes in the soon to be released new version of Evolved Caching, 1.9.17. This version will include a new setting to allow you to use common merged asset filenames giving you the freedom to deploy new CSS and JS file changes at will with CSS/JS merging enabled. Evolved Caching will automatically re-generate the merged files for you, so needing to refresh the full page cache when for instance updating some styles or functionality with no page HTML changing has become a thing of the past!
If you are interested in purchasing a copy of Evolved Caching, our advanced Magento Varnish and full page cache solution, then please visit our store here to find out everything you need to know before buying.