For years, service workers have promised us a feeling of a native app straight in the browser. While specific parts of it are true, such as access to device hardware (gyroscope, orientation sensor, etc.) or background sync, we're still far cry from the native feel in areas such as push notifications, which don't work at all in iOS, and especially offline support. While it's fun to have options and experiment on private, small projects, we can't really consider technologies to be production-ready when they don't support half the devices out there.
With that in mind, service workers also come with a lot of baggage. And we've found that out in a hard way.
First, you start developing your app, include service worker because it's a cool new thing to do, you want offline support or definitely want to have all the stuff they bring as an option to use. Months go by, you release v1 of the app and users start rolling in. As it's the first version, things are bound to change, so you implement the first couple of changes. You maybe change some copy around, some links, but soon you get a report that you have a huge bug discovered by one of your users. Maybe something potentially catastrophic for your database, it happens.
Fear not, you patch it up and go about your day. Months go by, and you release v2 of the app, market it like crazy and it reaches some top lists of this and that, and same users that entered your app a couple of months ago, and never again, land on your page and load a completely cached version from the last time they visited, together with any hardcoded values, bugs, funnel changes... essentially a snapshot from the past.
By the time you realize what you have done, you've already saved a snapshot of the app in the arbitrary time to thousands of devices, unable to wipe the cache on their devices, and just sit and wait for them to potentially open your older, less secure version of the app from months ago.
The way service worker works is when users land on your website for the 2nd time, it loads all assets and files from SW and THEN checks if you have pushed a new SW update in the meantime. If it finds one, it schedules it to be loaded next time you open the website. To make matters worse, normal refresh won't load the new SW content, but you have to close the session (i.e. close all website tabs currently open, or whole browser) and reopen the website to load the new version.
By following this article:
I found out that you can insert an action into this process of discovering the new version of SW. The problem is that you can either notify users that a new version is available and leave it up to them to click Load new version which will reload the website properly, or you can force a refresh when the browser figures out that a new SW version is available and installed, which can be after a couple of seconds and well into the time when the app was already interactive, meaning that user started to do something.
Usually, early in the live of an app, updates could be released several times a day, which means users could get a prompt or hard refresh multiple times a day when they land on a website, which is also not a good option.
Other way around, we leave ourselves open to the ghosts of the past by giving users the option to load a new version of the site or not. This way malicious users could take advantage of the app in its pre-patched state.
The worst thing is, when you decide to change your approach, you still have all the old users cached on your previous decision and they don't get the memo that they should reload as soon as they open the site.
Now, when you think about it, it becomes obvious that this is how native apps work from the start. You have a version that is the latest and a lot of previous versions that people have installed, and are still using. But the web isn't native.
As leob mentioned in the comments (thanks!) some apps force users to update to new versions even in the native environment. Banking apps first come to mind, which just confirms that the issue exists and if security is an important priority for us, that we have to address it in a creative way.
Many years ago, Web solved the issue where users had to install a new version of software on their devices, where we had to incentivize them to update or upgrade, and support legacy versions with both features and bugfixes. We approach web development with a different mindset than native development. We KNOW we can push updates very quickly to 100% percent of our users, and we are used to pushing experimental features, knowing very well that we can patch them up as we go or remove them fairly quickly if they turn out to be bad ideas. Including service workers turn the tables around once again, by introducing fragmentation, legacy support, and fear of the unknown on the internet, which is something that should be avoided at all costs.
Sure, if we create just a couple of versions all of which are perfect, this is a non-issue, but let's be real, those apps don't exist. So how do you deal with these issues if you still want to keep offline support? Do you use service workers at all? Let me know!