12

We build a flutter web app and deployed it via firebase hosting. Unfortunately, we didn't configure any caching settings in our initial deploy.

Now we deployed a newer version of our website but people still get the old website shown form the first deploy. What we tried so far:

Adding version no. to our index.html:

<"script src="main.dart.js?version=1" type="application/javascript"></script>

Adding meta Data in our header in index.html:

  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
  <meta http-equiv="Pragma" content="no-cache" />
  <meta http-equiv="Expires" content="0" />

In our firebase.json we added the following headers:

"headers": [
      {
        "source": "**",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "max-age=10"
          }
        ]
      }
    ]

All of these attempts were without any luck. We think that the problem is that the newer version doesn't have those entries in the files. How can we force this to update to our newest version? We even consider opening a new firebase project if that might help.

Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
Gizmo
  • 121
  • 1
  • 4

4 Answers4

13

Try this:

In your flutter app, in the index.html within the web folder, add a version number after the src="main.dart.js

So your new line will look like this:

<script src="main.dart.js?version=1" type="application/javascript"></script>

Then increment the version number to 2, etc before you do each build.

update june 2021: add this line in index.html as the last script in the body

bm888
  • 541
  • 5
  • 10
  • 2
    thank you, I actually didn't see in docs and just assumed that the new deployed was replacing the one before the messages from terminal are `finalizing version...`, `version finalized`, `releasing new version...`, `release complete`.. just now I realize "version.." hahah. Many thanks – Vincenzo Jul 17 '20 at 12:51
  • This didn't work for me. It still requires a refresh or two before updating (no difference). – August Kimo Jun 22 '21 at 03:11
3

I see Flutter now include this script by default in index.html if project is created recently which has serviceWorkerVersion element which updates the version when compiling:

<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();
}
aldobaie
  • 1,387
  • 10
  • 15
1

If you do not want to use the server worker caching, you can provide --pwa-strategy=none. Otherwise, the app will update after the new version has been downloaded and the page revisited.

Example:

flutter build web --release --pwa-strategy=none

It will Generate a service worker with no body. This is useful for local testing or in cases where the service worker caching functionality is not desirable

By default, it is set to offline-first: Attempt to cache the application shell eagerly and then lazily cache all subsequent assets as they are loaded. When making a network request for an asset, the offline cache wil be preferred.

Reference:

iqfareez
  • 555
  • 7
  • 21
0

When you build flutter web then in directory build/web generated a version.json file. just increase build_number and version in this file.