100

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?

zhangjinzhou
  • 2,461
  • 5
  • 21
  • 46

3 Answers3

185

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 version of angular ( for example Angular 8,9,10) the command is :

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

For the latest version of angular ( from angular 11 to angular 14) the command is reverted back to older format:

ng build  --aot --output-hashing=all
Joel Joseph
  • 5,889
  • 4
  • 31
  • 36
  • 1
    It works. Thank you for the solution. Could you please explain what situations could cause the problem? As I mentioned, the problem doesn't happen to all updates. – zhangjinzhou Mar 28 '19 at 18:18
  • @zhangjinzhou updated the answer with explanation , please mark it as answer if it helps you – Joel Joseph Mar 29 '19 at 06:28
  • 1
    Thanks for the explanation! – zhangjinzhou Mar 29 '19 at 17:16
  • I have the same issue. After each build/deployment I have to clear cache. Could you please tell me where should I add the above command?In angular side or devOps side? – Arj 1411 Sep 04 '19 at 07:07
  • 1
    Thanks. If I use this command, does it affect only the current application or entire browser? – Arj 1411 Nov 19 '19 at 05:12
  • @JoelJoseph, how do you add cache-busting for lazy-loaded styles? – vlodko Mar 18 '20 at 10:19
  • how does one test to see if this is actually working? – jgritten Mar 30 '20 at 16:32
  • ok, cache-busting works fine when you open the application initially, but does it behave when you duplicate a tab with latest version? In my scenario I get one from the previous versions. – Superiom Oct 09 '20 at 09:27
  • I tried this but getting Unknown option: '--output-hashing' angular 9 – Miroo Jan 27 '21 at 17:39
  • 8
    unfortunately this din't work for me, latest CLI already adds outputHashing:all in angular.json for all environments. :( – minigeek Sep 07 '21 at 12:29
  • 1
    i am using both option in my angular.json.. it was working, but after intregrating the ngsw service wroker, it is now showing the cache issue,? what can be the issue now? – Sunil Garg Oct 22 '21 at 11:55
  • Same issue declared by @SunilGarg , any solutions? – Androidian Feb 28 '22 at 19:08
  • 1
    and please make sure the index.html has – Irfan Soetedja Jun 22 '22 at 04:20
  • Maybe I'm misunderstanding your update, but when I go to https://angular.io/cli/build it is still showing the --output-hashing syntax. – dmoore1181 Jul 06 '22 at 17:44
  • 1
    @dmoore1181 they changed it at Angular 8 and then again reverted it back at Angular 11 with updates . So i have updated my answer as per the doc now – Joel Joseph Jul 07 '22 at 10:40
20

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:
Angular - Prod Build not generating unique hashes
sed in-place flag that works both on Mac (BSD) and Linux
RE error: illegal byte sequence on Mac OS X
Inline if shell script
How to loop over files in directory and change path and add suffix to filename
Is it possible to build separate CSS file with angular-cli?

Alejo JM
  • 921
  • 7
  • 12
  • Isaac, i don't have for Win, but you can easily make a docker for doing that – Alejo JM Feb 16 '21 at 17:29
  • @AlejoJM, I know.. this answer is quite old. But the script for renaming the javascript files is not working. Does no rename no file! excutes silently – k.vincent Oct 14 '21 at 10:46
  • hello @k.vincent you need to check your dist directory structure, the commands assume your dist folder have the app dist/index.html, if you have your dist/{appName} the commands will fail – Alejo JM Oct 16 '21 at 17:45
  • Yes I do have different structure like: dist/{appName}/{lang}. Does this means, that it works just for following structure: dist/ – k.vincent Oct 18 '21 at 09:23
  • What does your angular.json look like?? Could you please add it to your answer – Collin Nov 14 '22 at 22:34
  • getting " i was unexpected at this time." with this :( also tried changing the path in the _js command as suggested.. – Collin Nov 14 '22 at 22:54
14

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
Kurtis Jungersen
  • 2,204
  • 1
  • 26
  • 31