Something that has grabbed my interest for a long time is the concept of Progressive Web Apps (PWA). I’ve attempt to use PWA features in previous projects but I’ve always failed to really harness the benefits that a PWA can give. Every previous attempted failed because of my complete misunderstanding of the PWA life-cycle and how to integrate it well with the build system.
I’m not gonna talk about the PWA life-cycle in this article as it’s very well documented and I can’t explain it any better. Jake Archibald explains it best, read his article here.
In order to properly understand PWAs I decided to dive right in and make a simple ToDo list using React (my go to front end framework). Instead of using one of the many great Service Worker tools that can plug straight into React I went it alone, not because I don’t think they are good but because they hide all of the complexity of creating Service Worker. The tools also can’t create a bespoke service worker and can only use preset caching strategies.
I was really interested in creating a service worker ‘infrastructure’ that could would facilitate the growth of a service worker. I have a really low tolerance for code faff when I am developing, which I think is a pretty common feeling which is why there are so many powerful build tools. To reduce faff I made sure to integrate my service worker development into my webpack build.
I thought I would share my the things I did wrong in the hope I save someone else the pain.
Using waitUntil rather than respondWith
In the life-cycle of a PWA you have to respond to the oninstall and onactive events by using waitUntil but on the onfetch event you have to use respondWith. My mistake was responding to all of the events with waitUntil, annoyingly this gives you really funky behaviour and works in some cases but not in others. It got me so frustrated that I had to ask Stack Overflow which isn’t something I do often.
Trying to use indexedDB
indexedDB API kinda sucks and its the only way you can store data locally in the service worker. I initially tried to use indexDB without any helpers until came over this article, a Google Developer blog that uses a helper library because the raw API is so hard to get your head around. I chose to use idb-keyval which is an idb API which pretty much mimics the simple localStorage API, I would highly suggest using it.
Serving cached content while developing
When you are developing you always want to be serving the freshest content from the network but in production you will be regularly serving the data from the cache. I got round this by adding a __TIME__ variable that is passed into the service worker by webpack. This causes the browser to recognize the service worker as new every time webpack rebuilds. Importantly it does this even if only the React App is updated, ensuring that that the new bundle will always be served. Chrome also has some great debugging tools which force the install of the new SW every reload.
Support for PWAs on iOS is weird
iOS support for PWAs has come a long way but it is still quite different. It is important to learn the different support that different platforms have before you start. The key differences I found are are that there is no install prompt allowed on iOS. You also cant ask for notification permission but it is implied when the app is installed.