vue.jswebpackservice-workerworkboxworkbox-webpack-plugin

Is correct to call the service worker from main.js file or from index.html?


I'm trying to configure a custom service workers on Vuejs with Webpack but it's not completely working with the events or workbox (depending where I'm calling the sw.js file.

Following workbox guide from Google I've configured the SW to be registered and caching data but as I mentioned before depending on where I call the SW is doing wrongs things (or maybe I'm just dumb).

For example, if I register the file SW on index.html like this:

index.html

<script>
    // Check that service workers are registered
    if ('serviceWorker' in navigator) {
        window.addEventListener('load', () => {
            navigator.serviceWorker.register('service-worker.js').then(registration => {
                // registration.pushManager.subscribe({ userVisibleOnly: true, 
                //   applicationServerKey: key });
                console.log('SW registered: ', registration);
            }).catch(registrationError => {
                console.log('SW registration failed: ', registrationError);
            });
        });
    }
</script>

... my SW is registered but it's unable to catch events (offline and online) on the SW file showed below (service-worker.js) BUT I'm able to use workbox:

service-workers.js

import store from './store/index';

window.addEventListener('online', () => {
  console.log('Ando online compa');
  store.dispatch('IndexedDB/prueba');
});

window.addEventListener('offline', () => {
  console.log('Ando offline compa');
  store.dispatch('IndexedDB/prueba');
});

window.addEventListener('push', (event) => {
  const title = 'Get Started With Workbox';
  const options = {
    body: event.data.text(),
  };
  event.waitUntil(window.registration.showNotification(title, options));
});

workbox.core.skipWaiting();
workbox.core.clientsClaim();
workbox.precaching.precacheAndRoute(self.__precacheManifest);

... If I remove the script tag from index.html and put a call on the main.js and modify the service-worker.js like this:

main.js

import './vapidHelper';
import Vue from 'vue';
import './plugins/vuetify';
import VueSocketIO from 'vue-socket.io';
import App from './App.vue';
import router from './router';
import store from './store';
import './axiosConfig';
import initDB from './indexedDB/IndexedDB';
import './service-worker'; // <---- LINE

Vue.config.productionTip = false;
...

service-worker.js

import store from './store/index';

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('service-worker.js').then((registration) => {
      // registration.pushManager.subscribe({ userVisibleOnly: true, 
      //   applicationServerKey: key });
      console.log('SW registered: ', registration);
    }).catch((registrationError) => {
      console.log('SW registration failed: ', registrationError);
    });
  });

  window.addEventListener('online', () => {
    console.log('Ando online compa');
    store.dispatch('IndexedDB/prueba');
  });

  window.addEventListener('offline', () => {
    console.log('Ando offline compa');
    store.dispatch('IndexedDB/prueba');
  });

  window.addEventListener('push', (event) => {
    const title = 'Get Started With Workbox';
    const options = {
      body: event.data.text(),
    };
    event.waitUntil(window.registration.showNotification(title, options));
  });
}

workbox.core.skipWaiting();
workbox.core.clientsClaim();
workbox.precaching.precacheAndRoute(self.__precacheManifest);

... On this situation, I'm able to hear the events, but I'm UNABLE to use workbox (I receive an error on console that it's undefined.)


Do you have an idea what could be doing wrong?


Solution

  • I think you have confused some things here, let me explain :)

    Service Worker and the web application/web page itself DO NOT share the same execution context. If you define a variable in your SW script, your "normal" JavaScript on the page cannot access it and vice versa. They are COMPLETELY separate.

    For this reason, if you put something like this:

    import store from './store/index';
    

    in your service-worker.js (Service Worker script), it DOES NOT mean the same thing as having the same line of code in your main.js. You CANNOT dispatch Vuex actions from SW script.

    How can you communicate from SW to "main bundle"? Use postMessage. With postMessage you can send JSON messages from the page to the SW and from the SW to the page. The handler of the messages can then dispatch Vuex actions etc.

    Does this clear things up for you?