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.

Service Worker weird caching

See original GitHub issue

Is this a bug report?

Yes

Did you try recovering your dependencies?

Yes

Which terms did you search for in User Guide?

https://github.com/facebook/create-react-app/issues/2398

Environment

Environment Info:

System: OS: macOS High Sierra 10.13.6 CPU: x64 Intel® Core™ i5-5257U CPU @ 2.70GHz Binaries: Node: 9.10.0 - /usr/local/bin/node Yarn: 1.10.1 - /usr/local/bin/yarn npm: 5.6.0 - /usr/local/bin/npm Browsers: Chrome: 69.0.3497.100 Firefox: 62.0.3 Safari: 12.0 npmPackages: react: ^16.5.2 => 16.5.2 react-dom: ^16.5.2 => 16.5.2 react-scripts: 2.0.4 => 2.0.4 npmGlobalPackages: create-react-app: 2.0.3

Steps to Reproduce

(Write your steps here:)

  1. Clone https://github.com/gabrielmicko/react-create-app-pwa. It is almost a clean app of react-create-app.
  2. Install dependencies. yarn install. Create a build. yarn run build.
  3. Run serve -s build (if you don’t have serve yarn global add serve), or node server.js.
  4. Open localhost:5000. You should see service worker precaching files.
  5. Do some change in the App.js and run yarn run build again.
  6. Refresh the page and check your console. You should see the new files. It will log an “Update happened” message.
  7. Refresh the page to see the updates.
  8. Can’t see the changes I made.

Expected Behavior

After refreshing the page at point 7. I should see my changes.

Actual Behavior

I see the old version of my app.

(Write what happened. Please add screenshots!)

Reproducible Demo

https://www.youtube.com/watch?v=Hl5HbZ0TWoY

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:25
  • Comments:71 (14 by maintainers)

github_iconTop GitHub Comments

118reactions
Timercommented, Oct 5, 2018

You need to close all tabs or fully close the browser to see the changes reflected. A page reload will not reflect the changes.

60reactions
EddiGcommented, May 27, 2019

@sky93 With CRA v3 you can post a message SKIP_WAITING to the service worker to trigger skip waiting.

// index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";

ReactDOM.render(<App />, document.getElementById("root"));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.register({
  onUpdate: registration => {
    const waitingServiceWorker = registration.waiting

    if (waitingServiceWorker) {
      waitingServiceWorker.addEventListener("statechange", event => {
        if (event.target.state === "activated") {
          window.location.reload()
        }
      });
      waitingServiceWorker.postMessage({ type: "SKIP_WAITING" });
    }
  }
});

But usualy you want ot ask user before doing reload. I used wrapping service worker registration into the React context:

import React from "react";
import * as serviceWorker from "./serviceWorker";

const ServiceWorkerContext = React.createContext();

function ServiceWorkerProvider(props) {
  const [waitingServiceWorker, setWaitingServiceWorker] = React.useState(null);
  const [assetsUpdateReady, setAssetsUpdateReady] = React.useState(false);
  const [assetsCached, setAssetsCached] = React.useState(false);

  const value = React.useMemo(
    () => ({
      assetsUpdateReady,
      assetsCached,
      // Call when the user confirm update of application and reload page
      updateAssets: () => {
        if (waitingServiceWorker) {
          waitingServiceWorker.addEventListener("statechange", event => {
            if (event.target.state === "activated") {
              window.location.reload()
            }
          });

          waitingServiceWorker.postMessage({ type: "SKIP_WAITING" });
        }
      }
    }),
    [assetsUpdateReady, assetsCached, waitingServiceWorker]
  );

  // Once on component mounted subscribe to Update and Succes events in 
  // CRA's service worker wrapper
  React.useEffect(() => {
    serviceWorker.register({
      onUpdate: registration => {
        setWaitingServiceWorker(registration.waiting);
        setAssetsUpdateReady(true);
      },
      onSuccess: () => {
        setAssetsCached(true);
      }
    });
  }, []);

  return <ServiceWorkerContext.Provider value={value} {...props} />;
}

function useServiceWorker() {
  const context = React.useContext(ServiceWorkerContext);

  if (!context) {
    throw new Error(
      "useServiceWorker must be used within a ServiceWorkerProvider"
    );
  }

  return context;
}

export { ServiceWorkerProvider, useServiceWorker };

The only additional change required in the serviceWorker.js file of CRA if you want to register service worker from the React application. You need to get rid of the window.onload event waiting in the register function :

// serviceWorker.js
export 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.href);
    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/facebook/create-react-app/issues/2374
      return;
    }

    // We are not waiting for window's load event as it was for the create-react-app template
    // because we register a service worker in the React app that runs after window loaded
    // and the load event already was emitted.
    const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;

    if (isLocalhost) {
      // This is running on localhost. Let's check if a service worker still exists or not.
      checkValidServiceWorker(swUrl, config);

      // Add some additional logging to localhost, pointing developers to the
      // service worker/PWA documentation.
      navigator.serviceWorker.ready.then(() => {
        console.log(
          "This web app is being served cache-first by a service " +
            "worker. To learn more, visit http://bit.ly/CRA-PWA"
        );
      });
    } else {
      // Is not localhost. Just register service worker
      registerValidSW(swUrl, config);
    }
  }
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Chrome service worker not intercepting cached requests
The behavior described above is caused by the in-memory cache in Chrome's rendering engine Blink. All requests served from the in-memory ...
Read more >
Understanding Service Workers and Caching Strategies
If any single file is not cached, then the service worker is not installed. So, it is important to make sure that there...
Read more >
Service worker caching and HTTP caching - web.dev
A service worker intercepts network-type HTTP requests and uses a caching strategy to determine what resources should be returned to the ...
Read more >
Using Service Workers - Web APIs | MDN
A service worker functions like a proxy server, allowing you to modify requests and responses replacing them with items from its own cache....
Read more >
Strategies for Service Worker Caching for Progressive Web ...
Service worker caching strategies before and after deployment for react apps. ... Do not cache certain pages to avoid weird behavior.
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