In previous versions of the Angular service worker implementation, one of the config options was "routing"
. This can be seen in this unanswered SO question, was referenced in this Angular CLI issue, and the best remaining documentation seems to be the blog post by Stephen Fluin (on the Angular team), as well as the I/O talk from Alex Rickabaugh (from Google).
With Angular 5, the ServiceWorkerModule
has been well built-out, and most of the configuration can now be handled using the ngsw-config.json
file. However, there is no longer any mention of how to handle redirection for routes, anywhere in the angular.io guide, or in the documentation. So I end up with the following problem: when I have visited my app and go offline, I can still access the app when visiting it directly: https://jackkoppa.github.io/cityaq-sw-issue. However, upon load the app redirects to the search
route, and most users would be trying to load from a URL like https://jackkoppa.github.io/cityaq-sw-issue/search?cities=Shanghai (for simplicity, I'm just talking about Chrome desktop & mobile, for now, and in Incognito when possible).
When you try to visit that URL while offline, you immediately get 504 - Gateway Timeout. This is happening because the service worker has only cached the index, and doesn't know that other routes should redirect to the index so that it can load. I'm confident that previous iterations of the Angular service worker implementation could have handled this scenario, by setting up redirects to the index for given routes. Is there a way to handle this redirect in the current, Angular 5+ ngsw-config.json
, or in the generated ngsw.json
file? Barring that, how should a workaround be handled in a separate service worker JS file?
A routed Angular application has one singleton instance of the Router service. When the browser's URL changes, that router looks for a corresponding Route from which it can determine the component to display.
To access the route parameters, we use route. snapshot , which is the ActivatedRouteSnapshot that contains information about the active route at that particular moment in time. The URL that matches the route provides the productId . Angular uses the productId to display the details for each unique product.
Adding a service worker to an Angular application is one of the steps for turning an application into a Progressive Web App (also known as a PWA). At its simplest, a service worker is a script that runs in the web browser and manages caching for an application. Service workers function as a network proxy.
TL;DR: I've identified at least two issues causing breakage in my case; you can use this build script for now to try my fix, and see the app work offline here. Further testing & pull requests needed.
While I've been unable to find a documented answer, here's what I've been able to find thus far, in stepping through the ngsw-worker.js
file, as well as reading the @angular/service-worker
commit history.
The new ServiceWorkerModule
approach to "routing" is to take any "navigation" request (i.e. a non-index route on the same domain), and re-run the handleFetch
method, but now pointing to the index.html
request (source). This should work fine, given an SPA should be able to redirect to the URL once it has retrieved its cached files for the index.
So the problems that are causing my site above to fail when offline must not be directly related to routing, and I've found 2 thus far. Correcting these with a workaround has allowed me to get my app working mostly as expected. With the repro steps in the original question, cityaq is now working, while I've reproduced the original, failing site at cityaq-sw-issue.
The issues:
Hosted versions of an Angular app, where the --base-href
flag is set from the CLI, list absolute URLs for their service worker resources. When comparing requests to these resources, ngsw-worker.js
is expecting relative URLs
baseHref
is getting included in the resource URLs when ngsw.json
is generated (source)Of the 3 available "states" that the ngsw-worker.js
can be in, in my experience, EXISTING_CLIENTS_ONLY
seems to bet set incorrectly.
ngsw-worker.js
will no longer attempt to retrieve cached resources (source), and in my testing under what seem to be "correct" circumstances, the app still enters this state even when the only change is removing an internet connectionWhile I put together a PR for issue #1, and wait for some help understanding issue #2, I'm using a workaround build script to modify ngsw-worker.js
after it's generated. Warning: it's ugly & definitely modifies the intended "safe" behavior of setting EXISTING_CLIENTS_ONLY
. However, for my app, it does allow correct offline performance both when running locally (http-server
), and deploying to a live URL (GitHub pages, in my case).
To use the workaround: (Angular 5, tested w/ Angular 5.2.1)
npm install replace-in-file --save-dev
build/fix-sw.js
package.json
:"scripts": { ... "sw-build": "ng build --prod && node build/fix-sw", "sw-build-live": ng build --prod --base-href https://your-url.com/ && node build/fix-sw" ... }
npm run sw-build cd dist http-server -p 8080
npm run sw-build-live
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With