1
votes

I own quackr.io and have run into some trouble with users not seeing the new version of my code. quackr is a PWA (Angular SSR + Service worker) deployed onto Firebase hosting.

Whenever I deploy a new version, anyone who has viewed the site previously will see the old version. If you do a hard refresh you will see the new version. However if you do another normal page refresh it will revert back to the old version.

  • Page refresh: Receive old version
  • Hard refresh: Receive new version (but get the old version as soon as i do a normal refresh again)
  • Unregister service worker in chrome and do a normal refresh: Receive new version (but also get the old version as soon as i do a second refresh).
  • I've cleared all browser cache, cookies & storage. Again, this works for the initial refresh but not any subsequent ones.

Here's my firebase.json (i was hoping adding no-cache to the service worker js it would invalidate upon deploying but it didn't work):

{
  "hosting": {
    "public": "dist/browser",
    "headers": [
    {
      "source": "/@(ngsw-worker.js|ngsw.json)",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "no-cache"
        }
      ]
  } 
  ],
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "function": "ssr"
      }
    ]
  },
  "functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint",
      "npm --prefix \"$RESOURCE_DIR\" run build"
    ]
  }
}

ngsw-config.json:

{
  "index": "/index.html",
  "appData": {
    "name": "quackr.io",
    "description": "v2.0"
  },
  "assetGroups": [{
    "name": "app",
    "installMode": "prefetch",
    "resources": {
      "files": [
        "/favicon.ico",
        "/index.html",
        "/*.css",
        "/*.js"
      ]
    }
  }, {
    "name": "assets",
    "installMode": "lazy",
    "updateMode": "prefetch",
    "resources": {
      "files": [
        "/assets/**"
      ]
    }
  },
  {
    "name": "fonts",
    "resources": {
      "urls": [
        "https://fonts.googleapis.com/**"
      ]
    }
  }]
}

https://quackr.io/ngsw-worker.js

Any help would be appreciated, thanks guys!

1

1 Answers

1
votes

You will need to use Angular's service worker update functionality, which will watch for any new changes in the app, and then either refresh the page or notify the user about the updates and give them the option to refresh themselves:

see this example:

constructor(
        private swUpdate: SwUpdate,
        private snackbar: MatSnackBar
    ) {
        this.swUpdate.available.subscribe(evt => {
            const snack: any = this.snackbar.open(`Updates Available`, 'Reload');

            snack.onAction().subscribe(() => {
                window.location.reload();
            });

            snack.setTimeout(() => {
                snack.dismiss();
            }, 6000);
        });
    }

Original Docs:
https://angular.io/api/service-worker/SwUpdate

More info:
https://alligator.io/angular/service-worker-updates/

Here is my Firebase.json file

{
  "hosting": {
    "public": "dist/myApp",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "headers": [
      {
        "source": "**/*.@(eot|otf|ttf|ttc|woff|woff2|font.css)",
        "headers": [
          {
            "key": "Access-Control-Allow-Origin",
            "value": "max-age=31557600"
          }
        ]
      },
      {
        "source": "**/*.@(js|css)",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "max-age=31557600"
          }
        ]
      },
      {
        "source": "**/*.@(svg|ico|json|mp3)",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "max-age=31557600"
          }
        ]
      }
    ],
    "rewrites": [
      {
        "source": "**",
        "function": "ssr"
      }
    ]
  },
  "functions": {
    "predeploy": [
      "npm --prefix %RESOURCE_DIR% run lint",
      "npm --prefix %RESOURCE_DIR% run build"
    ],
    "source": "functions"
  },
  "emulators": {
    "functions": {
      "port": "5005"
    }
  },
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  }
}