# Working with Service Workers

We're using Service Workers for two main purposes:

  1. To cache out static and dynamic data feeds, to make them available offline (opens new window)
  2. To run offline data sync.

To achieve the first point, we're using sw-precache (opens new window) from Google, and for the second, Vanilla JS with a little help from sw-toolbox (opens new window)

# Making things happen

The service-worker source code for vue-storefront is pre-compiled with Babel presets and all is stored in an additional theme-specific Service Worker in src/{themename}/service-worker/index.js. This file is attached to service-worker.js generated by sw-toolbox.

After changing anything in {themename}/service-worker/index.js, despite you're in yarn dev auto reloading mode, you need to do two things:

  1. Recompile app (which regenerates service-worker): yarn build

  2. Reload Service Worker in Dev Tools (in Chrome, just click "Unregister" and reload the page, and a new Service Worker will be installed).

How to work with service-workers in Chrome

# Communication with the app

The application can speak to the Service Worker using the event bus, and only doing so. Please take a look at /core/lib/sw.js where we have the following method:

export function postMessage(payload) {
  if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
    // check if it's properly installed
    navigator.serviceWorker.controller.postMessage(payload);
    return false;
  } else {
    // no service workers supported push the queue manualy
    return true;
  }
}

It allows you to send data to the Service Worker. For example, when the order is placed (/core/store/modules/checkout):

  /**
   * Add order to sync. queue
   * @param {Object} product data format for products is described in /doc/ElasticSearch data formats.md
   */
  [types.CHECKOUT_PLACE_ORDER] (state, order) {
    const ordersCollection = StorageManager.get('orders')
    const orderId = entities.uniqueEntityId(order) // timestamp as a order id is not the best we can do but it's enough
    order.id = orderId.toString()
    order.transmited = false
    order.created_at = new Date()
    order.updated_at = new Date()

    ordersCollection.setItem(orderId.toString(), order).catch((reason) => {
      console.error(reason) // it doesn't work on SSR
      sw.postMessage({ config: config, command: types.CHECKOUT_PROCESS_QUEUE }) // process checkout queue
      console.info('Order placed, orderId = ' + orderId)
    }) // populate cache
  },