I have an angular/nodejs application in which a User can see a list of resources, update them, create them, and delete them (a basic CRUD application). I want to turn this into a PWA so the user can work offline. It must :
- Cache the assets (html, css …)
- Cache the result of GET requests
- Store the POST/PUT/DELETE requests to dispatch them later when connection is available.
So, first, I tried to add Angular’s Service Worker to my app following the documentation here : https://angular.io/guide/service-worker-getting-started
ng add @angular/pwa
It worked well for the first two points : While offline I could still consult the list of resources. But POST/PUT/DELETE requests all failed, as it only caches non-mutating requests
Then I stumbled upon this tutorial which describes how to extend the Angular Service Worker.
Using this code :
importScripts('./ngsw-worker.js'); self.addEventListener('fetch', (event) => { console.log('fetch event !') // Here do something to store request if method is POST/PUT/DELETE });
My custom fetch event is never fired because inside ngsw-worker.js
is already defined a ‘fetch’ event handler that catches the event.
If I declare my listener before Angular’s one :
self.addEventListener('fetch', (event) => { console.log('fetch event !') // Here do something to store request if method is POST/PUT/DELETE }); importScripts('./ngsw-worker.js');
Then I can see the log, however the offline mode doesn’t work anymore, I believe it’s because Angular’s ‘fetch’ listener is not triggered.
In conclusion, it seems that Angular’s Service Workers might not be the best solution for my use case. I’ve come across this resource that explains how to store POST/PUT requests but it doesn’t mention Angular.
Is there any other way to override angular’s service worker to store requests ? Or should I use another technology that would meet my needs, if any ? Thanks,
Advertisement
Answer
The problem here is not about angular’s service workers, it is a common problem which actually service workers can’t solve.
The PWA structure let the browsers to cache the app itself (.css .html .js files, images and so son). All these are static data which are retrieved with GET
HTTP requests.
Now, when we use the PWA structure to cache some data we GET
from a rest API, we are doing something a bit tricky… it works, ok.
The problems with calls which modify data in offline mode are more… think to concurrency between changes performed by different users. More simply, think to the following calls sequence
GET /data/42 // to retrieve an object POST /data/42 // to update the object GET /data/42 // to retrieve the same object
when online we expect that the first and the third calls (actually the same call) have two distinct response. How could a service worker replicate this scenario when in off line mode? It should at least know the logic of the called API, but even if we teach the logic to our service worker, how could it predict errors which could be raised during the second and the third calls?
The proper way to handle data in a PWA which plans to work with data in off line mode as well, is to implement a client side data layer (using localStorage
or IndexedDB
) which, when offline, remembers the changes attempts and try to sync them when back to on line mode.