Angular app has to clear cache after new deployment

JavascriptAngularNginxDeployment

Javascript Problem Overview


We have an Angular 6 application. It’s served on Nginx. And SSL is on.

When we deploy new codes, most of new features work fine but not for some changes. For example, if the front-end developers update the service connection and deploy it, users have to open incognito window or clear cache to see the new feature.

What type of changes are not updated automatically? Why are they different from others?

What’s the common solution to avoid the issue?

Javascript Solutions


Solution 1 - Javascript

The problem is When a static file gets cached it can be stored for very long periods of time before it ends up expiring. This can be an annoyance in the event that you make an update to a site, however, since the cached version of the file is stored in your visitors’ browsers, they may be unable to see the changes made.

Cache-busting solves the browser caching issue by using a unique file version identifier to tell the browser that a new version of the file is available. Therefore the browser doesn’t retrieve the old file from cache but rather makes a request to the origin server for the new file.

Angular cli resolves this by providing an --output-hashing flag for the build command.

Check the official doc : https://angular.io/cli/build

Example ( older versions)

ng build --prod --aot --output-hashing=all

Below are the options you can pass in --output-hashing

  • none: no hashing performed
  • media: only add hashes to files processed via [url|file]-loaders
  • bundles: only add hashes to the output bundles
  • all: add hashes to both media and bundles

Updates

For the newer version of angular ( for example Angular 10) the command is now updated :

ng build --prod --aot --outputHashing=all

Solution 2 - Javascript

for me adding:

    ng build --aot --output-hashing=all

to the build commands is not enough, when you have your app behind a CDN and a good cache nginx config.

1- The first thing was remove the cache for html files (nginx):

    location ~ \.(html)$ {
        add_header Pragma "no-cache";
        add_header Cache-Control "no-store";
        add_header strict-transport-security "max-age=31536000";
        add_header X-Frame-Options "SAMEORIGIN";
        try_files $uri $uri/ /index.html;
    }

for the static files (js/css ...) leave cache working (network performance / usability):

    location ~ \.(css|htc|less|js|js2|js3|js4)$ {
        expires 31536000s;
        add_header Pragma "public";
        add_header Cache-Control "max-age=31536000, public";
        try_files $uri $uri/ /index.html;
    }

2- Leave dev/prod builds exaclty the sames, for testing purpose. The final build dev command:

	ng build --env=dev --aot=true --output-hashing=all --extract-css=true 

3- We need on every deploy the client browser load all javascript files from the server not from the cache, even if the deploy was a minor update. Is like the angular have some bugs with this: https://github.com/angular/angular-cli/issues/10641 and happend to me.

I ended using the power of bash, this are my scripts for kill the cache on every development (prod/dev) using package.json file:

"scripts": {
 ...
    "deploy_dev": "ng build --env=dev --aot=true --output-hashing=all --extract-css=true && npm run add_date",
    "deploy_prd": "ng build --prod && npm run add_date",
    "add_date": "npm run add_date_js && npm run add_date_css && npm run rm_bak_files",
    "add_date_js": "for i in dist/*; do if [ -f $i ]; then LC_ALL=C sed -i.bak 's:js\":js?'$(date +%H%M%m%d%y)'\":g' $i; fi done",
    "add_date_css": "sed -i.bak 's:css\":css?'$(date +%H%M%m%d%y)'\":g' dist/index.html",
    "rm_bak_files": "find dist -name '*.bak' -exec rm -Rf {} \\;"
},

commands explanation:
add_date_js: find and replace to all files "js" with "js?{date+%H%M%m%d%y}"
add_date_css: find and replace in dist/index.html "css" with "css?{date+%H%M%m%d%y}"
rm_bak_files: remove all .bak files (network performance)

Those sed commands works on both GNU/BSD/Mac.

links:
https://stackoverflow.com/questions/58930327/angular-prod-build-not-generating-unique-hashes?noredirect=1&lq=1
https://stackoverflow.com/questions/5694228/sed-in-place-flag-that-works-both-on-mac-bsd-and-linux
https://stackoverflow.com/questions/19242275/re-error-illegal-byte-sequence-on-mac-os-x
https://stackoverflow.com/questions/4986109/inline-if-shell-script
https://stackoverflow.com/questions/20796200/how-to-loop-over-files-in-directory-and-change-path-and-add-suffix-to-filename
https://stackoverflow.com/questions/42370854/is-it-possible-to-build-separate-css-file-with-angular-cli

Solution 3 - Javascript

While the accepted answer above will work, this adjustment should be made in angular.json, under configurations => <my-env-name> => outputHashing => set to all (for production environments).

Simplified example:

{
  "projects": {
    "<my-project>": {
      "architect": {
        "build": {
          "configurations": {
            "<my-env-name>": {
              "outputHashing": "all"
            }
          }
        }
      }
    }
  }
}

And as mentioned in said post, the available options for this config:

> * none: no hashing performed > * media: only add hashes to files processed via [url|file]-loaders > * bundles: only add hashes to the output bundles > * all: add hashes to both media and bundles

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionzhangjinzhouView Question on Stackoverflow
Solution 1 - JavascriptJoel JosephView Answer on Stackoverflow
Solution 2 - JavascriptAlejo JMView Answer on Stackoverflow
Solution 3 - JavascriptKurtis JungersenView Answer on Stackoverflow