Search code examples
flutterserviceworkerversion

How do I replace `serviceWorkerVersion` with `{{flutter_service_worker_version}}` template token?


In my index.html in my flutter web app, I have a serviceWorker script. Flutter now complaints like this:

[   +3 ms] Warning: In index.html:60: Local variable for "serviceWorkerVersion" is deprecated. Use "{{flutter_service_worker_version}}" template token instead.

The <body> of the index.html is defined like this:

<body>
  <img src="img/logo_symbol.png" class="center"/>

  <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>
</body>

How do I replace serviceWorkerVersion with a {{flutter_service_worker_version}} template instead, as the warning suggests ?


Solution

  • Very similar to xleon's answer, but with some additional information for helping understand what's going on.

    <!DOCTYPE html>
    <html>
      <head>
        <base href="$FLUTTER_BASE_HREF">
        <meta charset="UTF-8">
        <meta content="IE=Edge" http-equiv="X-UA-Compatible">
        <meta name="description" content="My App">
        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black">
        <meta name="apple-mobile-web-app-title" content="my_app">
        <link rel="apple-touch-icon" href="icons/Icon-192.png">
    
        <!-- Favicon -->
        <link rel="icon" type="image/png" href="favicon.png"/>
    
        <title>my_title</title>
        <link rel="manifest" href="manifest.json">
      </head>
    
      <body>
        <!-- Include the flutter_bootstrap.js to ensure buildConfig is set correctly -->
        <script src="flutter_bootstrap.js" defer></script>
      </body>
    </html>
    

    When running flutter build web, the flutter_bootstrap.js file is created. This script is critical because it ensures that the necessary configuration is in place before the application is loaded. You can locate this file under the build files, and under the web directory:

    enter image description here

    The service worker is fully managed by "flutter_bootstrap.js"

    If you take a look at the flutter_bootstrap.js file, you will notice that it handles the service worker registration, including the loading parameters. Thus, you do NOT need to set the variable serviceWorkerVersion to {{flutter_service_worker_version}}. Doing so will remove some of the build errors we are seeing, but it isn't the proper solution.

    By using flutter_bootstrap.js, you leverage the built-in capabilities of the Flutter web build system to handle the service worker setup.

    enter image description here

    Special note - The bootstrap code is minified, or obfuscated, but I did happen to see references to wasm. I thought this was cool, so I just wanted to point that out.