Skip to content

Latest commit

 

History

History
77 lines (55 loc) · 3.69 KB

updates.md

File metadata and controls

77 lines (55 loc) · 3.69 KB

ServiceWorker and AppCache update process


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:

  1. Refresh the page (browser downloads new SW)
  2. 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 activated
  3. Refresh 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 :-)

Config

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.

Making sure ServiceWorker updates at all

This meant to be tested without adding any code to control SW's update process

  1. Load your webpage
  2. Build and deploy new version with something changed, add alert(1) for example
  3. Reload the webpage
  4. Close the tab of the webpage (make sure there is no more open tabs of this website)
  5. Open that webpage again in a new tab
  6. Check if you see alert(1)

For additional information about ServiceWorker life-cycle watch this video by Jake Archibald