diff --git a/packages/react-dev-utils/README.md b/packages/react-dev-utils/README.md index c63600b442..5daa9f062b 100644 --- a/packages/react-dev-utils/README.md +++ b/packages/react-dev-utils/README.md @@ -240,6 +240,10 @@ getProcessForPort(3000); On macOS, tries to find a known running editor process and opens the file in it. It can also be explicitly configured by `REACT_EDITOR`, `VISUAL`, or `EDITOR` environment variables. For example, you can put `REACT_EDITOR=atom` in your `.env.local` file, and Create React App will respect that. +#### `noopServiceWorkerMiddleware(): ExpressMiddleware` + +Returns Express middleware that serves a `/service-worker.js` that resets any previously set service worker configuration. Useful for development. + #### `openBrowser(url: string): boolean` Attempts to open the browser with a given URL.
diff --git a/packages/react-dev-utils/noopServiceWorkerMiddleware.js b/packages/react-dev-utils/noopServiceWorkerMiddleware.js new file mode 100644 index 0000000000..b6cee73506 --- /dev/null +++ b/packages/react-dev-utils/noopServiceWorkerMiddleware.js @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +'use strict'; + +module.exports = function createNoopServiceWorkerMiddleware() { + return function noopServiceWorkerMiddleware(req, res, next) { + if (req.url === '/service-worker.js') { + res.setHeader('Content-Type', 'text/javascript'); + res.send( + `// This service worker file is effectively a 'no-op' that will reset any +// previous service worker registered for the same host:port combination. +// In the production build, this file is replaced with an actual service worker +// file that will precache your site's local assets. +// See https://github.com/facebookincubator/create-react-app/issues/2272#issuecomment-302832432 + +self.addEventListener('install', () => self.skipWaiting()); + +self.addEventListener('activate', () => { + self.clients.matchAll({ type: 'window' }).then(windowClients => { + for (let windowClient of windowClients) { + // Force open pages to refresh, so that they have a chance to load the + // fresh navigation response from the local dev server. + windowClient.navigate(windowClient.url); + } + }); +}); +` + ); + } else { + next(); + } + }; +}; diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json index b5d5c12708..fa85d756de 100644 --- a/packages/react-dev-utils/package.json +++ b/packages/react-dev-utils/package.json @@ -21,6 +21,7 @@ "getProcessForPort.js", "InterpolateHtmlPlugin.js", "launchEditor.js", + "noopServiceWorkerMiddleware.js", "ModuleScopePlugin.js", "openBrowser.js", "openChrome.applescript", diff --git a/packages/react-scripts/config/webpackDevServer.config.js b/packages/react-scripts/config/webpackDevServer.config.js index 8d7eb0f1b5..9c12de0af3 100644 --- a/packages/react-scripts/config/webpackDevServer.config.js +++ b/packages/react-scripts/config/webpackDevServer.config.js @@ -11,6 +11,7 @@ 'use strict'; const errorOverlayMiddleware = require('react-error-overlay/middleware'); +const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware'); const config = require('./webpack.config.dev'); const paths = require('./paths'); @@ -72,6 +73,12 @@ module.exports = function(proxy, allowedHost) { setup(app) { // This lets us open files from the runtime error overlay. app.use(errorOverlayMiddleware()); + // This service worker file is effectively a 'no-op' that will reset any + // previous service worker registered for the same host:port combination. + // We do this in development to avoid hitting the production cache if + // it used the same host and port. + // https://github.com/facebookincubator/create-react-app/issues/2272#issuecomment-302832432 + app.use(noopServiceWorkerMiddleware()); }, }; };