Handling image caching with CakePHP (and asset compression)

From Yahoo! "Recommendations for speeding up your website" :

Expired headers are most often used with images, but they should be used for all components, including scripts, style sheets, and Flash components.

I follow the tips above with the Apache mod_expires module. My implementation is very similar to the HTML5 Boilerplate. See this .htaccess code .

Here is another quote from the same Yahoo! document:

Keep in mind that if you use the long Expires header of the future, you must change the component file name every time the component changes. At Yahoo! we often make this step part of the build process: the version number is embedded in the component file name, for example, yahoo_2.0.6.js.

I took care of this with my CSS and JavaScript files using the Mark Story Asset Compress plugin. It is just a matter of creating the shell of the Asset Compress shell.

Now for the two problems I ran into, both are related to images:

I have regular <img> tags on my sites, and I also have CSS background-image s. I currently do not have an elegant way to handle caching for either of these two types of images. For the <img> tags, I have this line in the "core.php" file:

 Configure::write('Asset.timestamp', 'force'); 

Despite the fact that it allows you to automatically handle caching of <img> tags (provided that the tags are generated using $this->Html->image(...) ), I do not consider this elegant for two reasons:

  • It uses a query string, which is not recommended .
  • The timestamp of the image is checked each time when accessing a particular view. Yes, you can cache the view, but you may want the images (images) in this view to be updated before the cached version of the view expires, so you will need to do whatever is necessary to initiate re-caching of the view, which I do not consider elegant.

Regarding the handling of CSS background-image s cache brute force, I have to manually update the LESS file. Definitely not elegant.

How should image caching be done using CakePHP and / or Asset Compress?

+4
source share
1 answer

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'); // won't work */ 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.

+3
source

Source: https://habr.com/ru/post/1490009/


All Articles