traccar / traccar-web

Traccar GPS Tracking System
https://www.traccar.org
Apache License 2.0
787 stars 1.09k forks source link

PWA regularly check for service worker updates and automaticially reload the page #1188

Closed jinzo closed 8 months ago

jinzo commented 8 months ago

Hi,

I was working on the https://github.com/traccar/traccar-web/issues/1169 issue and when deploying to staging I noticed that my PWA (on phone or open in the browser) does not actually update automatically like I would presume with the registerType: 'autoUpdate' config option set. After a bit of digging I actually found two things missing:

  1. The ServiceWorker itself did not check for an update when running. So I checked the documentation of VitePWA and adapted the code found there: https://vite-pwa-org.netlify.app/guide/periodic-sw-updates
  2. The actual webpage reload (after the ServiceWorker autoUpdates with step 1.) was not applied, therefore I set the immediate parameter to true as seen in the warning here: https://vite-pwa-org.netlify.app/guide/auto-update.html#automatic-reload

I tested this and now it behaves like I would expect it to behave. The Traccar PWA now checks every hour, if there is a new version and if found updates the ServiceWorker and reloads the webpage automaticially.

On a somewhat related note, just to be sure, so you do prefer automatic reload instead of the update-popup-and-user-clicks-for-reload?

tananaev commented 8 months ago

I thought they have a standard way to detect it automatically? And have a prompt option. How is registerType: 'autoUpdate' supposed to work?

jinzo commented 8 months ago

I was under that impression too, but apparently not - it did update itself (ninja edit, here I mean the ServiceWorker itself, not the PWA)/check (with autoUpdate option) on a new page load (either open a new tab or reload the current page). And that's how I understand this option alone works (it silently updates the ServiceWorker, not the webapp) on new page load (as this is actually not guaranteed with ServiceWorkers, there could be old ServiceWorkers open and somewhere in another tab and they would not get updated if a new tab loads a new version of a ServiceWorker). More info on updating ServiceWorkers: https://web.dev/articles/service-worker-lifecycle#updates Yes there is a prompt option, if you change registerType to 'prompt' instead of 'autoUpdate' (or omit it, 'prompt' is default) then it won't autoUpdate the ServiceWorker, but it will do it once the user clicks on the button (so it will update the ServiceWorker AND the pwa/web). But you still have to check every X ms, if you don't want to wait for (re)load of the webpage (which I'm not even sure how the customer can do, if it 'installs' the PWA on their phone for example). I personally would prefer the prompt option, so the PWA would just check every X ms if there is an update, and use the VitePWA prompt to let the user update if there is one.

EDIT: Sorry I really need to double check my comments before I send them, I was not very clear.

So, 'autoUpdate' option mostly tells the VitePWA to update the ServiceWorker (which is shared between all tabs from the same address) when it detects that there is a new version (as this ServiceWorker is shared between multiple tabs, auto updating is not automatic in the sense of how we always get the latest version of the webpage itself - bar caching). Nothing much about updating the Webpage/PWA. I guess that could be handled smartly too, but a reload is the most foolproof method there is - so we need to turn that on with the registerSW 'immediate' option, which reloads the webpage/PWA immediately when the ServiceWorker gets updated (automaticially with 'autoUpdate').

And if we don't want to wait for a webpage reload (or any of the other update triggers here: https://web.dev/articles/service-worker-lifecycle#updates) we need to check for ServiceWorker updates ourselves - and they have some edge case handling in the provided sample. Not sure why they are not doing that automatically TBH. I was expecting that too. But apparently not, as it's not even mentioned in the linked VitePWA docs.

tananaev commented 8 months ago

It seems like the browser should automatically check for updates:

https://web.dev/articles/service-worker-lifecycle#updates

Maybe I misunderstand something?

jinzo commented 8 months ago

The browser is checking for an update in this cases:

The last two are not applicable, as we are not pushing or syncing anything to the ServiceWorker and we are not chaging the ServiceWorker URL. Which means that only the first check is applicable, that happens when a user opens the webpage (either a new load, or an reload of the existing page). So in Traccars React App this means, that if a user has just one tab with it open, and uses it normally (and doesen't close the tab itself) he won't get the updated serviceworker/code until he opens a new one (or reloads the webpage). As a React App doesen't really navigate to a new page and therefore trigger a update. And in the case of a "Installed" PWA on a phone, this probably means force closing the "app" and opening it again.

tananaev commented 8 months ago

Why do we need the immediate: true? Would having prompt, as we discussed, fix it?

jinzo commented 8 months ago

Because of the warning here: https://vite-pwa-org.netlify.app/guide/auto-update.html#automatic-reload Quote from the yellow WARNING "Automatic reload is not automatic page reload, you will need to use the following code in your application entry point if you want automatic page reload:" My note: Automatic reload == 'autoUpdate'

Yes, having a prompt removes the need for immediate: true

tananaev commented 8 months ago
jinzo commented 8 months ago

Ok, just to be clear, so user configurable as a server setting? And do we make it just on/off or can the update check interval be configured too (eg. then I would still go with one setting, but if it's 0 then don't check, if it's more than 0 then use that as an update check interval)?

tananaev commented 8 months ago

We can make the interval configurable, if that's easy to implement. And zero means no updates. I think we should include it in the server attributes.

tananaev commented 8 months ago

I think if it works well, let's make it as a default, so some reasonable default value.

jinzo commented 8 months ago

So this is just a work in progress for now - but have to finish for today and comited to get some preliminary feedback.

I moved everything to a React component and adapted it to use plain Snackbar like other similar functionality in Traccar. While tweaking this I tested it plenty, and it works very well. What remains is figuring out why "useAttributePreference" is erroring out on me and do basic cleanup around that. I'm thinking 1h as the default value (as this is also the 'default' in Vite PWA documentation).

P.S: There is a big ol red warning that switching between 'autoUpdate' and 'prompt' while in production can be a pain, but from what I can see 'autoUpdate' did not make it into 5.9 so this won't be a problem: https://vite-pwa-org.netlify.app/guide/auto-update.html

jinzo commented 8 months ago

After stepping back from the monitor for a few minutes it dawned on me, that as the system is not initialized, I cannot access the user attributes. Moved it to a better location and it is ready for a review.

tananaev commented 8 months ago

Merged, thank you.

jinzo commented 8 months ago

Thank you very much for your patience.