Invalid Cache, Performance, and Web
It is generally believed that one of the most difficult tasks in programming is cache invalidation . However, with assets (js files, css files, images, etc.), which is not quite the true optimal logic for servicing network resources:
However, when applied to the network, there is one complication.
Consider a request /css/main.css containing:
body { background-image:url('../img/bar.gif'); }
This will obviously trigger the /img/bar.gif request when loading the css file. Assuming the image is served with the appropriate headers, there are only two ways to download the updated version of bar.gif :
- change css file contents
- change the folder where the css file is located
The first is problematic if it is not automated (and even if it is automated, it may go wrong), the second is easy.
Prefix version-prefix url -> there will never be a problem again
One easy way to solve the css / js / files problem is to make your build number part of the URL:
/v123/css/foo.css ^
You can do this by changing the function of the web root application helper, for example:
public function webroot($file) { $file = parent::webroot($file); if (Configure::read('debug')) { return $file; } return '/' . Configure::read('App.version') . $file; }
By the way, this is the same method of using cdn - perhaps the best you can do to improve interface performance.
That way, when you hit a version of your site, all assets get new URLs. Note that using this method, all reference assets should use relative URLs, not absolute ones:
.foo { background-image:url('../img/bar.gif'); }
Otherwise, the request for the css file is application-specific, but the link image is missing and will be read from the browser cache (if necessary) even with the new version of the application.
Achieving the same result, no changes to the file system
You can use a rewrite rule similar to the h5bp file to cache the file name cache if you do not want to change the folder structure
<IfModule mod_rewrite.c> RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^/v\d+/(css|files|js)/(.+)$ /$1/$2 [L] </IfModule>
This will mean that the url /v123/css/main.css serves the contents of /css/main.css at the time of the request.
Parsing css files is complicated
You mentioned in the comment
I think that the fact that changing one asset leads to reloading all assets is to unlock the transaction
If you do not release a new production version every minute - this will not be a problem (if you do not have GB of cached content, in this case .. you have different problems). The only way to have executable cache logic that is file specific is, for example, store each file on your site as sha1 of the file contents - apply to css files, which means replacing ../img/foo.gif with ../img/<hash of foo.gif contents>.gif .
There is nothing to stop using several methods, for example, with the following structure:
app webroot css img <- css assets only fonts img js
You can use the css, fonts and js version prefix; indirectly do the same for css images (provided that they use relative URLs of the form background-image:url('img/bar.gif'); ) without applying the same logic to other assets (custom avatars, their uploaded videos for cats, whatever).
Or use uris data for all images
This is what google does =).
At the end of the day, it becomes a choice between how complicated you want your build process to be and for what real benefits. Many users have empty browser caches , so itโs likely that for a casual user, the applicationโs cache logic will only apply to their current visit โ one of the main reasons that the entire resource cache expires is not so bad.