-
Notifications
You must be signed in to change notification settings - Fork 27.1k
Spawning Web Worker from previous AppVersion results in network fallback #57971
Description
Which @angular/* package(s) are the source of the bug?
service-worker
Is this a regression?
Yes
Description
Consider the following scenario:
- There is an existing Angular app with Service Worker
- An angular app has an on-demand web worker, that is cached via Service Worker
- A web worker is updated and a new version of an Angular app is deployed
- Existing client received a new version of an Angular app, but did not refresh an already opened tab
In that scenario, when an existing client, that already received a new version of an Angular app, but did not refresh an already opened tab, triggers a code path, where a new Web Worker is created, a Web Worker script is fetched from the network, instead of from a cache. Because of the nature of deployment, scripts from a previous version are not stored on a server, meaning a request for an old Web Worker script results in a 404 error, and eventually in a Web Worker initialization failure.
I'd expect a Service Worker to serve a Web Worker script for an old version if a fetch is initiated from an old Angular app version.
Please use a minimal reproduction repository and follow the steps in the video to simulate the issue.
ngsw-web-worker.webm
Please provide a link to a minimal reproduction of the bug
https://github.com/rozpuszczalny/ngsw-web-worker
Please provide the exception or error you saw
Worker emitted an Event on 'error' callback; service worker called network, where it should use cache.
Please provide the environment you discovered this bug in (run ng version)
Angular CLI: 18.2.6
Node: 20.12.0
Package Manager: npm 10.5.0
OS: linux x64
Angular: 18.2.6
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
... service-worker
Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1802.6
@angular-devkit/build-angular 18.2.6
@angular-devkit/core 18.2.6
@angular-devkit/schematics 18.2.6
@schematics/angular 18.2.6
rxjs 7.8.1
typescript 5.5.4
zone.js 0.14.10
Anything else?
We are experiencing such an issue in our production setup, which makes an update process quite painful for the users. Weirdly, for some users, simply reloading a tab does not solve the issue - we have to instruct the users to manually delete a Service Worker via chrome://serviceworker-internals. We still didn't identify nor reproduce that scenario where reload is not working.
Probably introduced by #42607, which was first released with Angular v12.
A possible solution is to check if clientId and resultingClientId are both set. If that's true, clientId should be used over resultingClientId. My crude testing showed (at least in Chrome browser) that resultingClientId is the client ID of a newly created web worker, and clientId is the client ID of a tab that spawned a web worker.
Since resultingClientId is relevant when opening a new tab, I've tested and noticed that clientId is set to an empty string when opening a website in a separate tab. However, opening window.open('/', '_top') sets both clientId and resultingClientId - similar to a web worker scenario. Unfortunately, location.reload() also sets both clientId and resultingClientId, which further complicates a potential solution.
| const clientId = event.resultingClientId || event.clientId; |