question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

index.html cache issue

See original GitHub issue

Library Affected: workbox-webpack-plugin@4.2.0 with workbox-build@4.3.1

Browser & Platform: all browsers

Issue or Feature Request Description: Hi there, we’ve got service worker enabled for caching purposes and we also have notification bar in app which informs user about its new version. This notification bar also includes button to update app by click 😃

registerServiceWorker.js of CRA framework with little modifications has following code:

const isLocalhost = Boolean(
  window.location.hostname === "localhost" ||
    // [::1] is the IPv6 localhost address.
    window.location.hostname === "[::1]" ||
    // 127.0.0.1/8 is considered localhost for IPv4.
    window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
)

export default function register(config) {
  if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
    // The URL constructor is available in all browsers that support SW.
    const publicUrl = new URL(process.env.PUBLIC_URL, window.location)
    if (publicUrl.origin !== window.location.origin) {
      // Our service worker won't work if PUBLIC_URL is on a different origin
      // from what our page is served on. This might happen if a CDN is used to
      // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
      return
    }

    window.addEventListener("load", () => {
      let isInitialServiceWorker = false
      if (!navigator.serviceWorker.controller) {
        isInitialServiceWorker = true
      }
      const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`

      if (isLocalhost) {
        // This is running on localhost. Lets check if a service worker still exists or not.
        checkValidServiceWorker(swUrl, config)
      } else {
        // Is not local host. Just register service worker
        registerValidSW(swUrl, config)
      }

      navigator.serviceWorker.addEventListener("controllerchange", () => {
        if (navigator.serviceWorker.controller) {
          if (!isInitialServiceWorker) {
            window.location.reload()
          }
        }
      })
    })
  }
}

function registerValidSW(swUrl, config) {
  navigator.serviceWorker
    .register(swUrl)
    .then(registration => {
      registration.onupdatefound = () => {
        const installingWorker = registration.installing
        if (installingWorker == null) {
          return
        }
        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.
              console.log("New content is available; please refresh.")
              if (config && config.onUpdate) {
                config.onUpdate(registration)
              }
            } else {
              // At this point, everything has been precached.
              // It's the perfect time to display a
              // "Content is cached for offline use." message.
              console.log("Content is cached for offline use.")
            }
          }
        }
      }
      if (registration.waiting === null) {
        setInterval(() => registration.update(), 3600000)
      } else {
        // this needs to be done because of firefox, is it doesn't have
        // serviceWorker in installing state before app load
        const waitingWorker = registration.waiting
        if (waitingWorker.state === "installed") {
          if (navigator.serviceWorker.controller) {
            console.log("New content is available; please refresh.")
            if (config && config.onUpdate) {
              config.onUpdate(registration)
            }
          }
        }
      }
    })
    .catch(error => {
      console.error("Error during service worker registration:", error)
    })
}

function checkValidServiceWorker(swUrl, config) {
  // Check if the service worker can be found. If it can't reload the page.
  fetch(swUrl)
    .then(response => {
      // Ensure service worker exists, and that we really are getting a JS file.
      if (
        response.status === 404 ||
        response.headers.get("content-type").indexOf("javascript") === -1
      ) {
        // No service worker found. Probably a different app. Reload the page.
        navigator.serviceWorker.ready.then(registration => {
          registration.unregister().then(() => {
            window.location.reload()
          })
        })
      } else {
        // Service worker found. Proceed as normal.
        registerValidSW(swUrl, config)
      }
    })
    .catch(() => {
      console.log("No internet connection found. App is running in offline mode.")
    })
}

and I append this to resulted serviceWorker.js file for “update” app functionality

self.addEventListener('message', function(event) {
  // Force SW upgrade (activation of new installed SW version)
  if ( event.data === 'skipWaiting' ) {
    /* eslint-disable-next-line no-restricted-globals */
    self.skipWaiting();
  }
});

From time to time, users are reporting app unavailability with following error in console: SyntaxError: expected expression, got '<'

The whole problem is that sometimes index.html file is not replaced with the newest one, so it points to not-existing css/js files. How can it be possible?

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:7
  • Comments:14 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
jeffposnickcommented, Apr 26, 2021

@jackdbd, this has always been one of the more difficult things to explain in our docs, but workbox-build does support that use case out of the box, via the templatedURLs option.

You provide an object whose keys are the “real” URLs that should be used as a cache key, and whose values are an array of one or more glob patterns. Anything that matches the glob patterns will be used to generate a composite hash for the corresponding URL. This allows you to specify multiple files, updates to any of which are sufficient to cause the precached entry for the “real” URL to be updated.

So in your case, you might have:

const generateSWConfig = {
  // ...other options...
  templatedURLs: {
    '/': ['index.html', 'netlify.toml'],
  },
};

You can also do this “by hand” via additionalManifestEntries or via a manifestTransforms callback, but that’s the “built-in” way of doing it.

1reaction
ketysekcommented, Feb 27, 2020

@blephy what it will solve? The revision number was different than the previous one. Also I’m using create-react-app, can’t inject webpack.hash in index.html now.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to make index.html not to cache when the site ...
In the root web.config we specify that we don't want to the index.html to cache by setting the cache-control , Pragma and Expires...
Read more >
Fix the annoying web page caching issue, permanently
A quick but temporary solution to fix this cache issue is to force the browser to clear the cache, by pressing Ctrl +...
Read more >
Index.html is being cached making the whole app display ...
html. The compiled index.html in the 'build' folder, references the newly compiled main.<random 8 characters>.js. What's actually happening, ...
Read more >
Does Index.html Get Cached? - Maker's Aid
Yes, your single-page web application's index.html file gets cached by all browsers. But, by setting the Cache-Control directive in your web ...
Read more >
Caching directives for index.html is ignored
We are running a React SPA in static web apps, and want to disable caching of the index.html file. We have added a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found