Page freeze after service worker update with complex computed properties

Hi,

I’m using the Vue CLI + pwa plugin for my web app. I’m running into a problem where after an update and the new service worker is registered, any .vue file with semi-complicated computed properties causes the browser to hang and the CPU spikes (observed via task manager). If you force close the tab and then come back to the page it loads fine every time after that. It is only a problem right after the new service worker is registered. Has anyone run into this before or have any ideas? Is there anyway to track down if vue is stuck in an infinite loop? The browser and dev tools are completely locked up so I’m not sure how to track it down…

The code in my main app.vue for registering the SW:

if (process.env.NODE_ENV === 'production') {
                    var oSWOptions = {
                        registrationOptions: {
                            // see https://developers.google.com/web/updates/2019/09/fresher-sw
                            updateViaCache: 'imports',
                        },
                        ready () {
                            console.log(
                                'App is being served from cache by a service worker.\n' +
                                'For more details, visit https://goo.gl/AFskqB'
                            )
                        },
                        registered () {
                            console.log('Service worker has been registered.')
                        },
                        cached () {
                            console.log('Content has been cached for offline use.')
                        },
                        updatefound () {
                            console.log('New content is downloading.')
                        },
                        updated () {
                            console.log('New content is available; please refresh.')

                            localStorage.setItem('runAfterUpdt', true); // next page reload will check for this

                            var oNotif = _Sublib.goodNotifObj();
                            oNotif.msg = _Sublib.getLbl('update avail');
                            oNotif.img = _Sublib.getIcon('app update');
                            
                            oNotif.onClick.applyUpdt = true;
                            oNotif.clearOnClick = true;
                            oNotif.clearPermanent = true;

                            _Sublib.addAppNotif(oNotif);
                        },
                        offline () {
                            console.log('No internet connection found. App is running in offline mode.')
                        },
                        error (error) {
                            console.error('Error during service worker registration:', error)
                        }
                    } // oSWOptions



                    if ('serviceWorker' in navigator){
                        // NOTE: the code from register-service-worker.js didn't provide a way for me to check for updates / get access to the registration option
                        // copied / tweaked the code and not using their's any more. SRR 10.16.2019
                        //registerValidSW(`${process.env.BASE_URL}service-worker.js`, emit, oSWOptions.registrationOptions);
                            
                            var registrationOptions = oSWOptions.registrationOptions;
                            var swUrl = `${process.env.BASE_URL}service-worker.js`;

                            // NOTE: This code is copied / tweaked form register-service-worker.registerValidSW() so I can manally call a method to check for updates
                            var hooks = oSWOptions;
                            var emit = function (hook) {
                                var args = [], len = arguments.length - 1;
                                while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];

                                if (hooks && hooks[hook]) {
                                hooks[hook].apply(hooks, args)
                                }
                            }

                            // check for updates
                            navigator.serviceWorker
                                .register(swUrl, registrationOptions)
                                .then(registration => {
                                    _Sublib.serviceWorkerReg = registration;

                                    // set a time so I check for an update every so often
                                    setInterval(function(){
                                        if (_Sublib.serviceWorkerReg){
                                            _Sublib.serviceWorkerReg.update();
                                        }
                                    }, 60*60*1000); // checks every hour

                                    emit('registered', registration)

                                    if (registration.waiting) {
                                        emit('updated', registration)
                                        return
                                    }

                                    registration.update(); // checks for an update

                                    registration.onupdatefound = () => {
                                        emit('updatefound', registration)
                                        const installingWorker = registration.installing
                                        installingWorker.onstatechange = () => {
                                        if (installingWorker.state === 'installed') {
                                            if (navigator.serviceWorker.controller) {
                                            // At this point, the old content will have been purged and
                                            // the fresh content will have been added to the cache.
                                            // It's the perfect time to display a "New content is
                                            // available; please refresh." message in your web app.
                                            emit('updated', registration)
                                            } else {
                                            // At this point, everything has been precached.
                                            // It's the perfect time to display a
                                            // "Content is cached for offline use." message.
                                            emit('cached', registration)
                                            }
                                        }
                                        }
                                    }
                                })
                                .catch(error => {
                                    emit('error', error)
                                })
                            
                    } // serviceworker in navigatoin
                    // else {
                    //     // standard register (also does a check for udpates be default)
                    //     // NOTE: this only checks for updates on window.load via event listener
                    //     register(`${process.env.BASE_URL}service-worker.js`, oSWOptions); 
                    // }
                    
                } // production
                
            }, // registerSW

The service worker code:

/* eslint-disable no-console */

// see https://levelup.gitconnected.com/vue-pwa-example-298a8ea953c9 

// NOTE: the precache manifest list will be added to the top of this file on build

/**

 * The workboxSW.precacheAndRoute() method efficiently caches and responds to

 * requests for URLs in the manifest.

 * See https://goo.gl/S9QRab

 */

workbox.core.setCacheNameDetails({prefix: "cplite"});

self.__precacheManifest = [].concat(self.__precacheManifest || []);

workbox.precaching.suppressWarnings();

workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

//*****************************************************************************************************************************************************

/* The install event fires when the service worker is first installed.

   You can use this event to prepare the service worker to be able to serve

   files while visitors are offline.

*/

self.addEventListener("install", function (event) {

    //console.log('WORKER: install event in progress.');

    /* Using event.waitUntil(p) blocks the installation process on the provided

       promise. If the promise is rejected, the service worker won't be installed.

    */

    //self.skipWaiting(); // register / activate as soon as possible (forces the waiting service worker to become the active service worker.)

    // see https://stackoverflow.com/questions/51715127/what-are-the-downsides-to-using-skipwaiting-and-clientsclaim-with-workbox and vue.config/js

}); // install

//*****************************************************************************************************************************************************

/* The activate event fires after a service worker has been successfully installed.

   It is most useful when phasing out an older version of a service worker, as at

   this point you know that the new worker was installed correctly. In this example,

   we delete old caches that don't match the version in the worker we just finished

   installing.

*/

self.addEventListener("activate", function (event) {

    /* Just like with the install event, event.waitUntil blocks activate on a promise.

       Activation will fail unless the promise is fulfilled.

    */

    //clients.claim(); // tells it to immediately start processing things it can

    event.waitUntil(async function () {

        var oKeys = await caches.keys();

        await Promise.all(

                oKeys.map(function (key) {    

                    if (navigator.onLine && key.indexOf('cplite') < 0) {

                        return caches.delete(key);

                    }

                }) // oKeys.map

            ); // Promise.all

            

        // take control of all pages within the service workers scope. 

        // "This triggers a "controllerchange" event on navigator.serviceWorker in any clients that become controlled by this service worker." see https://developer.mozilla.org/en-US/docs/Web/API/Clients/claim

        //self.clientInformation.claim(); 

        clients.claim(); 

        // now send a message to the client to update the local storage and apply the update

        sendMsg2Client({ action: 'UPDATE' });

        

        console.log('SW Worker activate completed');

            

    }()); // event.waitUntil

}); // activate

//*****************************************************************************************************************************************************

function sendMsg2Client(oMsg) {

    // this uses the BroadCast Channel API. see https://developers.google.com/web/updates/2016/09/broadcastchannel

    const oChannel = new BroadcastChannel('cp'); // name MUST match name in CPMobileMain.js that listens for messages!

    oChannel.postMessage(oMsg);

    oChannel.close();

}

//*****************************************************************************************************************************************************

// listen for messages from the client

self.addEventListener('message', oMsg => {

    var oClientMsg = oMsg.data;

    if (oClientMsg.action == 'ACTIVATE') {

        self.skipWaiting();

    }

}); 


//*****************************************************************************************************************************************************

self.addEventListener('error', function (event) {

    console.log('SW Error', event);

}); // error

//*****************************************************************************************************************************************************

self.addEventListener('statechanged', function (event) {

    console.log('SW State Change', event);

}); // statechanged

When the user clicks on my notification that an update is available I call location.reload()