Shazwazza / ClientDependency

DEPRECATED. A library for managing CSS & JavaScript dependencies and optimization in ASP.Net
139 stars 65 forks source link

Browser Caching Issue #116

Closed skidmow closed 7 years ago

skidmow commented 7 years ago

I have a question around browser caching of CSS files. I use the helpers Html.RequiresCss("myfile.css") and @Html.Raw(Html.RenderCssHere()) to bundle my CSS files with Client Dependency.

When I update a CSS file, I deploy the file, increase the client dependency version via the ClientDependency.config file, delete the existing files from \App_Data\ClientDependency\ and restart the application pool. All apart form the app pool restart are suggested here: https://www.diplo.co.uk/blog/web-development/using-the-clientdependency-framework-in-umbraco/

However, I when I reload the website, my CSS changes are still cached by the browser and I must do a hard browser refresh (Ctrl + F5) to clear the cache and load the new styles. This means I can't be sure that other users are seeing the new styles and not their old browser cached styles.

How can I force a browser cache refresh automatically? For example you can traditionally do this by appending a query string to the CSS file path. I understand that Client Dependency changes the querystring itself when the version is updated, so I don't know why this method isn't working in the same manner. Do you experience the same issue and what can I do to fix it? This article suggests that it could be that the server is slow to catch up and is still sending a 304 to the browser: https://css-tricks.com/update-on-css-caching/. What are your thoughts?

Note that I am using Client Dependency 1.8.4 with Umbraco 7.4.3 and this affects all browsers - Chrome, IE and Firefox.

Many thanks, Nathan

Shazwazza commented 7 years ago

One primary purpose of CDF is to do the cache busting for you so that browsers do not cache. If you change the CDF (integer) version in the CDF config, this will force the browser to download with a new URL since the cache buster query string version will be used in the request.

It is not a requirement that you delete the App_Data CDF files when you change the version, the existing files will just be orphaned/unused files but of course you can delete them if you want.

Something must be odd with your configuration or setup because you should not need to do a hard reset. The only reason this might be is that the browser (or server) has cached the contents of your html page and is still rendering the old CDF urls in your script/link tags.

skidmow commented 7 years ago

OK thanks for the clarification. I don't have any output caching on the CSS files on the server, but there is a load balancer involved in the setup which I don't have access to. I expect this is the culprit. I'll see if I can get it investigated. Cheers

Shazwazza commented 7 years ago

It might be output caching on the pages that you are rendering or some other sort of caching that is rendering the same css/js link/script tags even if you've bumped the CDF changes, or the headers returned from your pages are letting the browser hard cache the contents - which is not abnormal since you probably want your page's html cached in the browser but in some cases you may want to return different headers for your pages if the CDF version has changed. CDF doesn't control any caching headers with regards to your html pages.

skidmow commented 7 years ago

Hi Shannon, just an FYI I can confirm the HTTP Response Headers were the cause of this as they were set to expire after 7 days. I think this is the IIS default. I'm going to have to read up on best practices but reducing the expiry time fixes the issue. As a note though, you must wait 7 days or whatever the expiry time was initially before the browser will fetch the headers again and use the new expiry duration. Therefore just changing the expiry time to immediately won't do anything until the previous response headers expire on the browser.

Shazwazza commented 7 years ago

You can force the browser to not use cache, either using f12 and open developer tools to disable cache or you can ctrl+f5 which will force reload everything.

What headers are you referring too? The HTML page headers or the DependencyHandler.axd headers? The thing is though, when you change the CDF version, the DependencyHandler URL changes and therefore nothing should be cached.

skidmow commented 7 years ago

Sorry for the slow response, this slipped under my radar. The issue is this:

You can set it in IIS under HTTP Response Headers - Set Common Headers. The above setting is to cache web content for 14 days.

I thought it was set to 14 days in IIS by default, but it appears this is a legacy setting in our application for optimization purposes. Umbraco out of the box does not include this setting. I have reduced it to 1 hour to still get some benefit from caching, but it does mean that changes to the CSS and JS files can take an hour to appear as the browser will cache the old client dependency file. What are the performance implications of setting the expiry to immediately? Is there another way around this that I am not seeing, such as the exclusion of specific items from this cache? I appreciate this is a wider subject beyond the client dependency application.

Many thanks

Shazwazza commented 7 years ago

Sorry I'm still a little confused on this. CDF URLs look like:

/DependencyHandler.axd?s=L3VtYnJh.......Y3RpdmUuanM7&t=Javascript&cdv=810

the cache busting part of it is cdv=810, this number is set in the CDF configuration. If you change this number, than the URL of CDF changes, this is the whole premise of how CDF performs it's cache busting. Because the URL changes, the headers returned shouldn't matter because it will be a brand new URL.

skidmow commented 7 years ago

I see what you mean. Should the cdv version number be the same as the version number set in the clientdependency.config file? Mine are different.

For example in the clientdependency.config file I have: <clientDependency version="329227899" fileDependencyExtensions=".js,.css" loggerType="Umbraco.Web.UI.CdfLogger, umbraco">

However on the front end output, it reads: /DependencyHandler.axd?s=L3VtYnJh.......Y3RpdmUuanM7&t=Javascript&cdv=14

FYI these are the versions of CDF that I am using:

<package id="ClientDependency" version="1.8.4" targetFramework="net45" />
<package id="ClientDependency-Mvc5" version="1.8.0.0" targetFramework="net45" />
Shazwazza commented 7 years ago

Yes it should definitely be. Perhaps your clientdependency.config isn't be used, please check your web.config, it may be that some old Nuget upgrade is no longer referencing that external file. it should look like: <clientDependency configSource="config\ClientDependency.config" />

skidmow commented 7 years ago

That was it. The reference was indeed missing. Thank you so much for your help on this.

Instead of the reference I just had this:

<clientDependency>
<!-- Full config documentation is here: https://github.com/Shazwazza/ClientDependency/wiki/Configuration -->
</clientDependency>

Looking into the source history on the web.config file, it was originally there when I installed Umbraco 7.2.0. Then when I upgraded to Umbraco 7.4.3, the reference was removed and the above 'empty' section was added at the bottom of the web.config file. I don't know if I did that myself or whether that was automatic with the nuget upgrade. Either way it's resolved now so thank you for this.

Shazwazza commented 7 years ago

I think the transform was an issue with a previous umb/cdf release so probably wasn't something you accidentally did. Glad we got to the bottom of this one :)