Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force cache refresh on flutter v3.0.1 web

In the current version of flutter 3.0.1 we have a service worker in index.html. So far, I cannot find any documentation on flutter.dev for how to force a cache refresh when screens or code has updated. The only way to refresh is using browser refresh buttons, etc.

There is a lot of outdated suggestions on SO to change the version number manually by appending something here or there, but that does not apply to the serviceworker. The service worker when running flutter build web automatically gets a new version number each time you build. This does not, however, force a cache refresh in the browser.

By default this service worker js is listening for a statechange and then calling console.log('Installed new service worker.'); This is only called when you click the browser's refresh button, so it is not helpful to prompt or force a refresh for new content.

I tried using flutter build web --pwa-strategy=none and this does not affect caching either.

Any bright ideas out there to force a refresh? In other websites I've built it was very easy to version css/js files, which would force a refresh without any user interaction, but I'm not seeing any clear paths with flutter build web.

This is the serviceWorker js in web/index.html.

After running flutter build web the var serviceWorkerVersion = null will become something like var serviceWorkerVersion = '1767749895'; when deployed to hosting and live on the web. However, this serviceWorkerVersion update does not force a refresh of content.

  <script>
    var serviceWorkerVersion = null;
    var scriptLoaded = false;
    function loadMainDartJs() {
      if (scriptLoaded) {
        return;
      }
      scriptLoaded = true;
      var scriptTag = document.createElement('script');
      scriptTag.src = 'main.dart.js';
      scriptTag.type = 'application/javascript';
      document.body.append(scriptTag);
    }

    if ('serviceWorker' in navigator) {
      // Service workers are supported. Use them.
      window.addEventListener('load', function () {
        // Wait for registration to finish before dropping the <script> tag.
        // Otherwise, the browser will load the script multiple times,
        // potentially different versions.
        var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
        navigator.serviceWorker.register(serviceWorkerUrl)
          .then((reg) => {
            function waitForActivation(serviceWorker) {
              serviceWorker.addEventListener('statechange', () => {
                if (serviceWorker.state == 'activated') {
                  console.log('Installed new service worker.');
                  loadMainDartJs();
                }
              });
            }
            if (!reg.active && (reg.installing || reg.waiting)) {
              // No active web worker and we have installed or are installing
              // one for the first time. Simply wait for it to activate.
              waitForActivation(reg.installing || reg.waiting);
            } else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
              // When the app updates the serviceWorkerVersion changes, so we
              // need to ask the service worker to update.
              console.log('New service worker available.');
              reg.update();
              waitForActivation(reg.installing);
            } else {
              // Existing service worker is still good.
              console.log('Loading app from service worker.');
              loadMainDartJs();
            }
          });

        // If service worker doesn't succeed in a reasonable amount of time,
        // fallback to plaint <script> tag.
        setTimeout(() => {
          if (!scriptLoaded) {
            console.warn(
              'Failed to load app from service worker. Falling back to plain <script> tag.',
            );
            loadMainDartJs();
          }
        }, 4000);
      });
    } else {
      // Service workers not supported. Just drop the <script> tag.
      loadMainDartJs();
    }
  </script>
like image 340
Zelf Avatar asked Nov 17 '25 08:11

Zelf


1 Answers

You can use a Firestore listener to a specific document or Firebase Remote Config in real time, to check if needs to clear the cache.

Once it needs to clear the webpage cache, simply run:

import 'dart:html' as html show window;
html.window.location.reload();

https://firebase.google.com/docs/remote-config

like image 79
Vitor Avatar answered Nov 20 '25 05:11

Vitor