Browser fetches ServiceWorker
file each time user navigates to your website. If new ServiceWorker
is found, browser immediately runs it along side with current SW. This new SW gets only install
event at this time, which allows it to prepare/cache assets of the new version. New SW doesn't start controlling pages until all tabs of your website are closed, this is by design in the ServiceWorker
.
AppCache
has slightly simpler update mechanism: browser also downloads manifest.appcache
on each navigation to your site (simplified) and if new AppCache
is available, browser installs new AppCache
and removes old one. This means that on a next page refresh browser will load files from the new AppCache
.
Sometimes, AppCache
is the root of confusion--one may just expect SW to have the same update process as AppCache
have. Another confusing thing could be Cmd/Ctrl+R
combination. One may think that it forces browser to update and activate SW. This is wrong, Cmd/Ctrl+R
doesn't updates or reloads into a new SW, it just tells to browser to bypass currently controlling ServiceWorker
.
If you have only 1 tab of your website opened, then this flow can update SW:
Refresh
the page (browser downloads new SW)Ctrl/Cmd+Refresh
the page (browser bypasses SW). Now current SW doesn't control any pages, so it will be discarded and new SW will be activatedRefresh
the page (new SW is now in place and controls the page)
This is how it works. Of course, there is a way to update SW/AppCache when you want it, you are the developer after all :-)
Tell to OfflinePlugin
to generate events for ServiceWorker
:
// offline-plugin config
new OfflinePlugin({
ServiceWorker: {
events: true
}
})
Tell to offline-plugin/runtime
to use life-cycle events and apply any update immediately:
// client-side code
const runtime = require('offline-plugin/runtime');
runtime.install({
onUpdating: () => {
console.log('SW Event:', 'onUpdating');
},
onUpdateReady: () => {
console.log('SW Event:', 'onUpdateReady');
// Tells to new SW to take control immediately
runtime.applyUpdate();
},
onUpdated: () => {
console.log('SW Event:', 'onUpdated');
// Reload the webpage to load into the new version
window.location.reload();
},
onUpdateFailed: () => {
console.log('SW Event:', 'onUpdateFailed');
}
});
There is a similar option for AppCache: AppCache: { events: true }
, but I don't recommend using it unless you really need to. AppCache's events are unstable because they behave differently in different browsers and some hacks have been applied to make it work as it does now. The events are unstable because they may fail to fire, or fire twice. These problems are mostly because AppCache is loaded in an iframe and every browser behaves different in this case (regarding events).
In general, AppCache events work and should work fine. But don't expect them to be bulletproof or something like that. This is why they are marked unstable.
This meant to be tested without adding any code to control SW's update process
- Load your webpage
- Build and deploy new version with something changed, add
alert(1)
for example - Reload the webpage
- Close the tab of the webpage (make sure there is no more open tabs of this website)
- Open that webpage again in a new tab
- Check if you see
alert(1)
For additional information about ServiceWorker
life-cycle watch this video by Jake Archibald