No More Posting New Topics!

If you have a question or an issue, please start a thread in our Github Discussions Forum.
This forum is closed for new threads/ topics.

Navigation

    Quasar Framework

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search

    [Solved] PWA force refresh when new version released?

    Framework
    22
    60
    53220
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • A
      amer1616 last edited by

      there is a great resources about this topic
      https://deanhume.com/displaying-a-new-version-available-progressive-web-app/
      https://stackoverflow.com/questions/52221805/any-way-yet-to-auto-update-or-just-clear-the-cache-on-a-pwa-on-ios

      1 Reply Last reply Reply Quote 0
      • ssuess
        ssuess last edited by

        Thanks, but the second link you sent is actually something I wrote the answer to myself, and it doesn’t address the service worker problem, it is a bit of a hacky workaround, and the most important problem with it is that it does not always reload all of the contents (because the service worker is holding on to the current context). That is why I am looking for a way to actually trigger the service worker itself to check. I am not sure if the bug is in the register-service-worker npm that quasar uses for this purpose, in quasar code itself, or something in my implementation. This is a punishingly frustrating thing to try to troubleshoot. There should be a way to force the service worker to check for an update, and then perform whatever actions are specified in the register-service-worker.jsfile. Currently the only way I can find to force that is with a window.location.reload(true) as mentioned above, but it suffers from the need to have the user trigger it and the dual reload problem if there is in fact an update.

        1 Reply Last reply Reply Quote 0
        • ssuess
          ssuess last edited by ssuess

          I have a solution finally!

          forceSWupdate () {
            if ('serviceWorker' in navigator) {
              navigator.serviceWorker.getRegistrations().then(function (registrations) {
                for (let registration of registrations) {
                  registration.update()
                }
              })
            }
          }
          

          This solves both of my problems above, and I can put it into a method that is either user triggered or programatically. Hope this helps someone else.

          A 1 Reply Last reply Reply Quote 1
          • C
            ChrisO last edited by ChrisO

            I’ll add my observations, because I think this will be a recurring issue for lots of people.

            From what I’ve seen, Quasar will automatically check for the existence of a new service worker when it loads. However by default, a PWA won’t start using the new service worker until it is completely shut down and restarted. Simply reloading, or even hard-refreshing the page won’t work (and PWAs in standalone mode don’t always have a refresh button available). This is particularly problematic on iOS at the moment - when you close a PWA, iOS “freezes” the state of the app rather than shutting it down. And there’s no way to easily shut down the app. I’ve found going into the settings for Safari and doing a full cache clear will let a new service worker take over the PWA, and the updated version will appear.

            Enabling the skipWaiting() setting (which can be done in the quasar.conf.js file) will the PWA to start using the new service worker as soon as possible. The observed behaviour flow: app loads up, PWA checks for new service worker, identifies a new one is available and installs it. If the page is reloaded or revisited, the new service worker will take over and the updated version will display. The updated version isn’t shown absolutely immediately, but it is shown pretty fast.

            One potential issue I’ve seen (not 100% confirmed). Using skipWaiting() in conjunction with lazy loading is a known potential risk: a new service worker might try to load content that is in control of the older service worker. We’ve seen new content load up, navigate to a different page, navigate back and the old version is displaying.

            Edit: iOS 13 (coming out in a couple of weeks) brings back the ability to force quit a PWA. That might also influence the decision of whether to use skipWaiting().

            1 Reply Last reply Reply Quote 1
            • A
              applecider @ssuess last edited by

              @ssuess Hello, will this work on normal vue.js app? without using quasar? Thank you in advance. I’m also dealing on how to refresh the page for cache refreshing whenever it detects new changes.

              ssuess 1 Reply Last reply Reply Quote 0
              • ssuess
                ssuess @applecider last edited by

                @applecider Yes these techniques really don’t have much to do with quasar itself (although there are a few quasar specific settings related to injecting options into workbox, you can just add those yourself).

                1 Reply Last reply Reply Quote 0
                • C
                  ChrisO last edited by

                  Further update now that that iOS 13 has been released.

                  I removed skipWaiting() and clientClaim() from our configuration settings. I can open our PWA and it will show the old version. After closing the app via the app switcher, when the app restarts, it has updated to the new version. iOS might close a suspended PWA after a certain amount of time has passed without any user action, although as with most things PWA related on iOS, information from Apple is scarce.

                  1 Reply Last reply Reply Quote 1
                  • P
                    PiotrG last edited by

                    Sorry to resurrect this old thread but I am having the same problems as some users above. I have a PWA with a custom service worker. In App.vue in a preFetch method, I read a file called version.json and compare that with a localstorage “version” property. If the localstorage is lower, I then create a Quasar Dialog that there is a newer version available and then do window.location.reload(true) when the user clicks “ok”. That all works, however it doesn’t fetch the latest app data. Only when I either close the app and reopen it or in a browser I do a ctrl-f5 to refresh.

                    When changing to generatesw instead of injectmanifest, thus eliminating my custom service worker (which I want because of various route caching strategies), quasar creates a red bar that a new version is available and when clicking that, it fetches the latest version of the app from the server.

                    Does anyone know how generateSW is doing this and how I could duplicate that functionality in my custom service worker?

                    dobbel ssuess 2 Replies Last reply Reply Quote 0
                    • dobbel
                      dobbel @PiotrG last edited by

                      @PiotrG

                      Thread with similar problem:
                      https://forum.quasar-framework.org/topic/6959/chrome-but-not-ff-nor-safari-randomly-fails-pwa-update/29?_=1604419034026

                      btw I would start new thread for this.

                      1 Reply Last reply Reply Quote 0
                      • ssuess
                        ssuess @PiotrG last edited by ssuess

                        @PiotrG I am pretty sure you are running into the same problem I was running into originally, which is that a simple reload will not work because you can’t let go of the app itself while you are using it without invoking the update method of your registration in navigator.serviceWorker see above for that code, and also remember that you must have skipWaiting and clientsClaim present in your service worker (they can be loaded into the service worker when using GenerateSW if you add workboxOptions: { skipWaiting: true, clientsClaim: true } in your quasar.conf.js file btw)

                        1 Reply Last reply Reply Quote 1
                        • T
                          turigeza last edited by

                          @ssuess Which one are you using right now ? The last one posted here …
                          https://forum.quasar-framework.org/topic/2560/solved-pwa-force-refresh-when-new-version-released/31?_=1605731186657

                          forceSWupdate () {
                            if ('serviceWorker' in navigator) {
                              navigator.serviceWorker.getRegistrations().then(function (registrations) {
                                for (let registration of registrations) {
                                  registration.update()
                                }
                              })
                            }
                          }
                          
                          1 Reply Last reply Reply Quote 0
                          • ssuess
                            ssuess last edited by

                            @turigeza I use the function above when I want to trigger an update from within my code, and within my service worker I have code that checks my local version number, clears localstorage, and then forces a reload. I also have to unfortunately check in SW for what browser we are using, because different browsers behave differently when reloaded. You can see that code and explanation in this thread: https://forum.quasar-framework.org/topic/6959/solved-chrome-but-not-ff-nor-safari-randomly-fails-pwa-update/41?_=1605780104096

                            metalsadman 1 Reply Last reply Reply Quote 1
                            • metalsadman
                              metalsadman @ssuess last edited by

                              @ssuess said in [[Solved] PWA force refresh when new version released?](/post

                              @turigeza I use the function above when I want to trigger an update from within my code, and within my service worker I have code that checks my local version number, clears localstorage, and then forces a reload.

                              Mind sharing the snippet

                              1 Reply Last reply Reply Quote 1
                              • ssuess
                                ssuess last edited by ssuess

                                I linked to it above, but here it is again in more or less final form (with domains changed):

                                import localforage from 'localforage'
                                
                                register(process.env.SERVICE_WORKER_FILE, {
                                  ready () {
                                    console.log('App is being served from cache by a service worker.')
                                  },
                                  registered (registration) { // registration -> a ServiceWorkerRegistration instance
                                    console.log('Service worker has been registered.')
                                    // console.log('scope: ' + registration.scope)
                                  },
                                  cached (registration) { // registration -> a ServiceWorkerRegistration instance
                                    console.log('Content has been cached for offline use.')
                                  },
                                  updatefound (registration) {
                                    console.log('New content is available; please refresh.')
                                    /* eslint-disable no-extra-boolean-cast */
                                    if (!!window.chrome) { // for chromium based browsers
                                      fetch('https://pwatest.mydomain.com/av.json?t=' + Date.now())
                                        .then(response => {
                                          response.json().then(function (data) {
                                            const r = confirm('There is a new version (' + data.version + ') available. Your version will be updated, alright? ' + data.message)
                                            if (r === true) {
                                              if (data.clearStorage === true) {
                                                localforage.clear().then(function () {
                                                  // Run this code once the database has been entirely deleted.
                                                  console.log('Database is now empty. so there now.')
                                                  location.reload(true)
                                                }).catch(function (err) {
                                                  // This code runs if there were any errors
                                                  console.log(err)
                                                })
                                              }
                                            } else {
                                              console.log('You pressed Cancel!')
                                            }
                                          })
                                          console.log('response:', response)
                                        })
                                        .catch(error => {
                                          console.error(error)
                                        })
                                      }
                                    },
                                    updated (registration) { // registration -> a ServiceWorkerRegistration instance
                                      console.log('New content is available; please refresh.')
                                      if (!window.chrome) { // for non chromium browsers
                                      fetch('https://pwatest.mydomain.com/av.json?t=' + Date.now())
                                        .then(response => {
                                          response.json().then(function (data) {
                                            const r = confirm('There is a new version (' + data.version + ') available. Your version will be updated, alright? ' + data.message)
                                            if (r === true) {
                                              if (data.clearStorage === true) {
                                                localforage.clear().then(function () {
                                                  // Run this code once the database has been entirely deleted.
                                                  console.log('Database is now empty. so there now.')
                                                  location.reload(true)
                                                }).catch(function (err) {
                                                  // This code runs if there were any errors
                                                  console.log(err)
                                                })
                                              }
                                            } else {
                                              console.log('You pressed Cancel!')
                                            }
                                          })
                                          console.log('response:', response)
                                        })
                                        .catch(error => {
                                          console.error(error)
                                        })
                                      }
                                    },
                                    offline () {
                                      console.log('No internet connection found. App is running in offline mode.')
                                    },
                                    error (err) {
                                      console.error('Error during service worker registration:', err)
                                    }
                                })
                                
                                1 Reply Last reply Reply Quote 2
                                • T
                                  turigeza last edited by

                                  @ssuess Thank you for sharing the code and explaining it as well.

                                  1 Reply Last reply Reply Quote 1
                                  • D
                                    danbars last edited by

                                    It seems that Quasar now supports this out of the box: https://quasar.dev/quasar-cli/developing-pwa/configuring-pwa#Reload-%26-Update-Automatically

                                    ssuess 1 Reply Last reply Reply Quote 1
                                    • ssuess
                                      ssuess @danbars last edited by

                                      @danbars Quasar supports loading clientsClaim and skipWaiting directives into the SW file, but for a number of reasons this is not enough. Also, while on supported platforms it will update your PWA, it will do so silently. I needed a way to do all of the following:

                                      • Control or initiate the update process
                                      • Set my own versioning
                                      • Notify users about updates
                                      • Perform actions related to the update
                                      • Work around platform and browser limitations and inconsistencies so that it works the same everywhere and without failure
                                      1 Reply Last reply Reply Quote 0
                                      • M
                                        Marin Vartan @Carlitos last edited by

                                        @carlitos thank you man, you save a lot of time

                                        1 Reply Last reply Reply Quote 0
                                        • Z
                                          zeppelinexpress last edited by

                                          Hi guys, I have a doubt, how does the browser know there is a new update? is the package-lock.json?
                                          just changing this:
                                          {
                                          “name”: “app”,
                                          “version”: “0.0.1”,

                                          is enough to automatically update on android/desktop browsers/installed versions?

                                          ssuess 1 Reply Last reply Reply Quote 0
                                          • ssuess
                                            ssuess @zeppelinexpress last edited by

                                            @zeppelinexpress when you build your project (for a PWA) there will be new cache signatures, which a PWA should read and then force an update. However, as mentioned above this is inconsistent across platforms and I have found it necessary to make my app check a version string that I set on the server and call the update mechanisms at that point which works everywhere. See the code examples above for what I use to make this work.

                                            1 Reply Last reply Reply Quote 1
                                            • First post
                                              Last post