Why My Content Served by PWA Service Worker Not Updating?
Have you been in following situations?
Your PWA website console log keeps saying:
New content is available; please refresh.
But refreshing just does not seem to work - old content and the log both stick.
For you who are in a hurry and cares just the solution, close and start your whole web browser, not just tabs, and content should be updated normally.
Why does this happen?
You are using service worker to make your website a PWA(Progressive Web App). The new content of your website is going to be served by a new-version service worker, but it is waiting to replace the old version. The way how your web browser maintains service worker lifecycle apparently gets in the way, however, it actually does you good.
Service Worker Lifecycle
Jake Archibald has written an excellent dive-in on service worker, and I think it definitely worth a read. To sum up briefly, a service worker lifecycle consists of following state:
stateDiagram [*] --> installing: js on page calls navigator.serviceWorker.register() note right of installing new service worker gets "install" event end note installed: installed/waiting installing --> installed: installEvent.waitUntil() got resolved promise installed --> activating: wait until earlier service worker controls zero client note right of activating new service worker gets "activate" event end note activating --> activated: activateEvent.waitUntil() got resolved promise note right of activated new service worker has fully come to power end note activated --> redundant: when replaced by a newer version redundant --> [*]
navigator.serviceWorker.register()is called, the script is downloaded and parsed, and service worker gets
installevent, where it will use a promise in
installEvent.waitUntil()to signal whether the install process succeed or not;
installEvent.waitUntil()got a resolved promise. If there has already been a service worker of a earlier version, web browser will keep our newcomer wait until the earlier one controlling zero client(a client here refers to mostly web pages in the service worker’s scope). Here is where your update blocks.
- activating: service worker got
activateevent, which means the old service worker has gone, if there was one. It’s time for our newcomer to do housekeeping stuff like flushing old cache and claiming existing pages. A promise in
activateEvent.waitUntil()is used to signal when things are done.
- activated: The service worker has fully come to power, and it will got events like
pushfrom claimed pages.
- redundant: Discarded, Either failed install, or it’s been replaced by a newer version.
Why Update Blocks
Web browsers keep new service worker waiting to avoid possible behavior conflict and incompatibility among two service workers of different version, and pages in their scope.
If browsers let our new service worker skip waiting, kick out and replace the outdated one immediately by default, already-opened tabs whose content and scripts are originally served by outdated service worker, may not work well with the new service worker, since their cache logic and program logic are designed to cooperate with the outdated service worker.
Thus, the browser choose a way with less surprises(shock).
Why normal refresh(
F5) not working?
Look at address bar. The address does not change before and after normal refresh, therefore, the tab remains to be a client of the outdated service worker.
If your visitor has only one tab of your website in his/her browser, then the outdated service worker will give its control right to the new one when the user navigate the tab to other website(zero client left).
If you are worrying about using a PWA library may keep users from getting updates, all you need to do is to keep calm and cool. New contents will get available when your visitors close and start their browsers again.
However, If the waiting is really drive you anxious, you may consider display a new-version-available message to your visitors, though keep in mind
skipWaiting may bring surprises discussed above.
Besides, force-reload(shift-reload, aka,
shift + F5) bypasses service worker entirely, the page loaded is not controlled by service worker in any way. This feature is in the service worker spec.