From 0a3829f0527955ed69db179e38a963fb20cf63ed Mon Sep 17 00:00:00 2001
From: Jeff Posnick <jeffy@google.com>
Date: Thu, 11 Oct 2018 12:18:56 -0400
Subject: [PATCH] Updates to clarify the "waiting" SW behavior.

---
 packages/react-scripts/template/README.md     | 36 ++++++++++---------
 .../template/src/serviceWorker.js             | 28 ++++++++-------
 2 files changed, 36 insertions(+), 28 deletions(-)

diff --git a/packages/react-scripts/template/README.md b/packages/react-scripts/template/README.md
index c591bbf0d..60acc1065 100644
--- a/packages/react-scripts/template/README.md
+++ b/packages/react-scripts/template/README.md
@@ -1896,16 +1896,32 @@ or unreliable network.
 If you do decide to opt-in to service worker registration, please take the
 following into account:
 
+1. After the initial caching is done, the [service worker lifecycle](https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle)
+controls when updated content ends up being shown to users. In order to guard against
+[race conditions with lazy-loaded content](https://github.com/facebook/create-react-app/issues/3613#issuecomment-353467430),
+the default behavior is to conservatively keep the updated service worker in the "[waiting](https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle#waiting)"
+state. This means that users will end up seeing older content until they close (reloading is not
+enough) their existing, open tabs. See [this blog post](https://jeffy.info/2018/10/10/sw-in-c-r-a.html)
+for more details about this behavior.
+
+1. Users aren't always familiar with offline-first web apps. It can be useful to
+   [let the user know](https://developers.google.com/web/fundamentals/instant-and-offline/offline-ux#inform_the_user_when_the_app_is_ready_for_offline_consumption)
+   when the service worker has finished populating your caches (showing a "This web
+   app works offline!" message) and also let them know when the service worker has
+   fetched the latest updates that will be available the next time they load the
+   page (showing a "New content is available once existing tabs are closed." message). Showing
+   this messages is currently left as an exercise to the developer, but as a
+   starting point, you can make use of the logic included in [`src/serviceWorker.js`](src/serviceWorker.js), which
+   demonstrates which service worker lifecycle events to listen for to detect each
+   scenario, and which as a default, just logs appropriate messages to the
+   JavaScript console.
+
 1. Service workers [require HTTPS](https://developers.google.com/web/fundamentals/getting-started/primers/service-workers#you_need_https),
    although to facilitate local testing, that policy
    [does not apply to `localhost`](http://stackoverflow.com/questions/34160509/options-for-testing-service-workers-via-http/34161385#34161385).
    If your production web server does not support HTTPS, then the service worker
    registration will fail, but the rest of your web app will remain functional.
 
-1. Service workers are [not supported](https://jakearchibald.github.io/isserviceworkerready/#moar)
-   in older web browsers. Service worker registration [won't be attempted](src/serviceWorker.js)
-   on browsers that lack support.
-
 1. The service worker is only enabled in the [production environment](#deployment),
    e.g. the output of `npm run build`. It's recommended that you do not enable an
    offline-first service worker in a development environment, as it can lead to
@@ -1919,18 +1935,6 @@ following into account:
    instructions for using other methods. _Be sure to always use an
    incognito window to avoid complications with your browser cache._
 
-1. Users aren't always familiar with offline-first web apps. It can be useful to
-   [let the user know](https://developers.google.com/web/fundamentals/instant-and-offline/offline-ux#inform_the_user_when_the_app_is_ready_for_offline_consumption)
-   when the service worker has finished populating your caches (showing a "This web
-   app works offline!" message) and also let them know when the service worker has
-   fetched the latest updates that will be available the next time they load the
-   page (showing a "New content is available; please refresh." message). Showing
-   this messages is currently left as an exercise to the developer, but as a
-   starting point, you can make use of the logic included in [`src/serviceWorker.js`](src/serviceWorker.js), which
-   demonstrates which service worker lifecycle events to listen for to detect each
-   scenario, and which as a default, just logs appropriate messages to the
-   JavaScript console.
-
 1. By default, the generated service worker file will not intercept or cache any
    cross-origin traffic, like HTTP [API requests](#integrating-with-an-api-backend),
    images, or embeds loaded from a different domain.
diff --git a/packages/react-scripts/template/src/serviceWorker.js b/packages/react-scripts/template/src/serviceWorker.js
index 46c98a440..012c322dd 100644
--- a/packages/react-scripts/template/src/serviceWorker.js
+++ b/packages/react-scripts/template/src/serviceWorker.js
@@ -1,12 +1,14 @@
-// In production, we register a service worker to serve assets from local cache.
+// This optional code is used to register a service worker.
+// register() is not called by default.
 
 // This lets the app load faster on subsequent visits in production, and gives
 // it offline capabilities. However, it also means that developers (and users)
-// will only see deployed updates on the "N+1" visit to a page, since previously
-// cached resources are updated in the background.
+// will only see deployed updates on subsequent visits to a page, after all the
+// existing tabs open on the page have been closed, since previously cached
+// resources are updated in the background.
 
-// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
-// This link also includes instructions on opting out of this behavior.
+// To learn more about the benefits of this model and instructions on how to
+// opt-in, read http://bit.ly/CRA-PWA.
 
 const isLocalhost = Boolean(
   window.location.hostname === 'localhost' ||
@@ -41,11 +43,11 @@ export function register(config) {
         navigator.serviceWorker.ready.then(() => {
           console.log(
             'This web app is being served cache-first by a service ' +
-              'worker. To learn more, visit https://goo.gl/SC7cgQ'
+              'worker. To learn more, visit http://bit.ly/CRA-PWA'
           );
         });
       } else {
-        // Is not local host. Just register service worker
+        // Is not localhost. Just register service worker
         registerValidSW(swUrl, config);
       }
     });
@@ -61,11 +63,13 @@ function registerValidSW(swUrl, config) {
         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.');
+              // At this point, the updated precached content has been fetched,
+              // but the previous service worker will still serve the older
+              // content until all client tabs are closed.
+              console.log(
+                'New content is available and will be used when all ' +
+                  'tabs for this page are closed. See http://bit.ly/CRA-PWA.'
+              );
 
               // Execute callback
               if (config && config.onUpdate) {
-- 
GitLab