3

I created Angular 6 app and hosting it using Apache on a remote server. Created a build with ng build --prod.

I noticed that when making changes and updating an html file - the page is being loaded from a cache and not from a new version of a file that is placed in Apache folder (using default configuration in Apache and nothing in Meta tags in HTML pages yet).

How to force reloading page on a client browser but only when there is a new version of the same page? (new changes to an existing site)

What are the best practices?

Joe
  • 11,983
  • 31
  • 109
  • 183
  • Try on windows: `CTRL + F5` or `CMD + R` on mac to refresh without using the browser's cache. – kemp Oct 09 '18 at 16:57
  • 1
    Thanks. I am thinking about other users that should get refreshed page automatically if something gets changed. – Joe Oct 09 '18 at 18:17
  • @kemp same here. CTRL+F5 is not an option. My system have many users spread acros the internet. I can't send they an email asking to refresh at every deploy. – Magno C Oct 13 '22 at 03:04

5 Answers5

1

I guess you are asking this question for the production environment not for development purpose.

If this is the case, then you can check the following:

  1. index.html file is not getting updated.

  2. check what cache expiration is getting set on the browser. It must be no-cache.

  3. How are you generating the building the code. If using angular-cli then the ng build will create a the chunk names with hash and it is different each time when the content is changed.

  4. check the cache header for lazy loaded module

Vivek Kumar
  • 4,822
  • 8
  • 51
  • 85
  • Ideally would like for both Dev and Prod to be refreshed (from end user point of view) soon as new feature is added (and index file or other files are modified). – Joe Oct 09 '18 at 18:31
  • What are you getting in the Response Header for the `cache-contro` and `expires`? It should be `cache-control: no-cache` and `expires: -1` – Vivek Kumar Oct 09 '18 at 18:46
  • I guess the apache server might be setting something different and that's why the browser is loading from cache. – Vivek Kumar Oct 09 '18 at 18:47
  • If `expires: -1` for your index file then the browser will never cache it and always download from server. – Vivek Kumar Oct 09 '18 at 18:49
  • This is all under Header -> Headers -> Response Headers (for the main page url - there are other parts of the page in the list as well): `HTTP/1.1 304 Not Modified Date: Tue, 09 Oct 2018 19:10:31 GMT Server: Apache/2.4.6 (Red Hat Enterprise Linux) Last-Modified: Tue, 09 Oct 2018 16:35:36 GMT ETag: "946-577ce53c9a03f" Accept-Ranges: bytes Content-Type: text/html; charset=UTF-8 Proxy-Connection: Keep-Alive Connection: Keep-Alive Age: 0` – Joe Oct 09 '18 at 19:14
  • You are getting `304` from your apache server. Meaning that the index.html is not changed. – Vivek Kumar Oct 09 '18 at 19:19
  • Google how to set set cache setting for file/dir in apache – Vivek Kumar Oct 09 '18 at 19:19
  • I am getting now `304`. Should I try to change something on a web page (index.html) and expect a different than `304`? – Joe Oct 09 '18 at 19:41
  • not on webpage but on apache conf setting. Your endgoal is to set the cache-control header. Which can be done via apache conf. I don't know how configure apache cache header – Vivek Kumar Oct 09 '18 at 19:45
  • Ok, but to prove if is Html (Angular) side or Apache side - what test can I perform to confirm 100%? (e.g. change index.html and expect different header details once open a web page?) – Joe Oct 09 '18 at 20:09
  • just check in your browser network tab for cache control response header. (either for index.html item or your domain name, generally the 1st item in network tab). – Vivek Kumar Oct 09 '18 at 20:54
  • Idea is that the index.html must never be cache because this file is very small so downloading it not problem also this file trigger other file to download. – Vivek Kumar Oct 09 '18 at 20:55
1

1) Hash Angular files while building

Angular has a built in hashing mechanism to ensure updated files are not cached. To activate this functionality you have to add the property "outputHasing": "all" to the build configurations in your angular.json file. Alternatively you can build your project with the command: ng build --output-hashing=all

2) Add server side Cache-Control headers

As @Khalid mentionned, Angular does not ensure the index.html file isn't cached. Server-side response headers can take up this task. Cache-Control is a header that you can configure on your web server to add to all outgoing requests, which will tell the browser and CDNs how to cache your content.

On Apache you should set these cache control headers in your main configuration file 'httpd.conf'. In case you can't access this file due to hosting limitations you can set it in your '.htaccess' file. To not cache the index.html file use following cache control headers:

#Initialize mod_rewrite
<FilesMatch "\.(html|htm)$">
  FileETag None
  <IfModule mod_headers.c>
    Header unset ETag
    Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
    Header set Pragma "no-cache"
    Header set Expires "Wed, 12 Jan 1980 05:00:00 GMT"
  </IfModule>
</FilesMatch>

NB: Make sure that the mod_headers are enabled in your main configuration file. Following line should be uncommented (without the #).

LoadModule headers_module modules/mod_headers.so

While calling the latest version of your page (f.ex. by refreshing without using cached content CTRL+SHIFT+F5) you should now see these cache control headers in your response headers. You can verify these headers in the Inspect > Network tab in your browser.

3) Handle previously cached files

All versions of your index.html file that were cached in your clients browser -before you added the new cache control headers- will still be cached. To overcome this issue you should use different URL's. This can be done by using a new domain name (as long as you do not care about SEO) or by adding a URL parameter (without touching SEO).

After building your Angular project as described above and adding this configuration on your Apache web server, users will always get the newest version of your page.

Nico
  • 216
  • 1
  • 5
  • The problem is not hashed JS files. The problem is index.html. As it name is the same, it will not be refreshed and will keep loading old JS files from cache even the new ones are there. – Magno C Oct 13 '22 at 03:09
  • That is correct. Step 2 (web server configuration) and 3 (handling previously cached files - cf. the index.html file you are talking about) explain how to overcome this issue. – Nico Nov 15 '22 at 10:18
0

When you build do this:

ng build --output-hashing=all

This should prevent changed files from caching.

danday74
  • 52,471
  • 49
  • 232
  • 283
  • 1
    Jesus! Again.... this will hash only JS files not index.html. When index.html is the same, it will not be refreshed and therefore it willl keep loading old JS files EVEN HASHED. – Magno C Oct 13 '22 at 03:06
0

You can use AOT Production build, by default have hashing enabled.

ng build --prod
Suresh Kumar Ariya
  • 9,516
  • 1
  • 18
  • 27
  • Used exactly this way but it is still getting cached old version of index.html file. – Joe Oct 09 '18 at 18:33
  • this will hash only JS files not index.html. When index.html is the same, it will not be refreshed and therefore it willl keep loading old JS files EVEN HASHED – Magno C Oct 13 '22 at 03:07
0

When using a production build ng build --prod, the cli will create a bundle with a hash value attached to each of your angular files. So if you ensure your index is not cached, it will refer to the files with the hashes. If the files have not changed, their hashes will be the same, and so it will load them from the cache. If they change, it will attempt to load the new files.

The remaining thing is to ensure that the index.html file is not cached, and this can be done by sending the no-cache headers, or using a dynamic file (e.g. php, jsp, ...) instead of *.html.

Khalid
  • 161
  • 4
  • Do yo have example of `no-cache` headers? – Joe Oct 09 '18 at 18:18
  • This answer goes into great details of how to set the no-cache headers: https://stackoverflow.com/questions/49547/how-to-control-web-page-caching-across-all-browsers – Khalid Oct 09 '18 at 18:26