diff --git a/docusaurus/docs/making-a-progressive-web-app.md b/docusaurus/docs/making-a-progressive-web-app.md index 0eb7d404edf..28429ecdc28 100644 --- a/docusaurus/docs/making-a-progressive-web-app.md +++ b/docusaurus/docs/making-a-progressive-web-app.md @@ -36,13 +36,34 @@ The [`workbox-webpack-plugin`](https://developers.google.com/web/tools/workbox/m is integrated into production configuration, and it will take care of generating a service worker file that will automatically precache all of your local assets and keep them up to date as you deploy updates. -The service worker will use a [cache-first strategy](https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#cache-falling-back-to-network) +By default, the service worker will use a [cache-first strategy](https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#cache-falling-back-to-network) for handling all requests for local assets, including [navigation requests](https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests) for your HTML, ensuring that your web app is consistently fast, even on a slow or unreliable network. -## Offline-First Considerations +### `workbox.config.js` + +If you require more control over the service worker generated by [`workbox-webpack-plugin`](https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin)'s `GenerateSW` class, a file called `workbox.config.js` can be added to the project root. + +```js +// workbox.config.js +module.exports = options => options; +``` + +The `options` argument passed to the exported function is passed to the [`GenerateSW`](https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin#generatesw_plugin_1) class constructor. + +E.g. to pass the default options provided by `create-react-app` with the `skipWaiting` option set to `true`: + +```js +// workbox.config.js +module.exports = options => { + options.skipWaiting = true; + return options; +}; +``` + +### Offline-First Considerations If you do decide to opt-in to service worker registration, please take the following into account: diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index e5a3e0b5374..00bc019fce6 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -82,6 +82,7 @@ module.exports = { appHtml: resolveApp('public/index.html'), appIndexJs: resolveModule(resolveApp, 'src/index'), appPackageJson: resolveApp('package.json'), + appWorkboxConfigJs: resolveApp('workbox.config.js'), appSrc: resolveApp('src'), appTsConfig: resolveApp('tsconfig.json'), appJsConfig: resolveApp('jsconfig.json'), diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index c1403a51920..758a128c926 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -54,6 +54,14 @@ const imageInlineSizeLimit = parseInt( // Check if TypeScript is setup const useTypeScript = fs.existsSync(paths.appTsConfig); +let workboxConfig = options => options; +// Get react-scripts configuration overrides if available +try { + workboxConfig = require(paths.appWorkboxConfigJs); +} catch (e) { + // Do nothing if we could not find a react-scripts configuration file +} + // style files regexes const cssRegex = /\.css$/; const cssModuleRegex = /\.module\.css$/; @@ -653,21 +661,23 @@ module.exports = function(webpackEnv) { // Generate a service worker script that will precache, and keep up to date, // the HTML & assets that are part of the Webpack build. isEnvProduction && - new WorkboxWebpackPlugin.GenerateSW({ - clientsClaim: true, - exclude: [/\.map$/, /asset-manifest\.json$/], - importWorkboxFrom: 'cdn', - navigateFallback: publicUrl + '/index.html', - navigateFallbackBlacklist: [ - // Exclude URLs starting with /_, as they're likely an API call - new RegExp('^/_'), - // Exclude any URLs whose last part seems to be a file extension - // as they're likely a resource and not a SPA route. - // URLs containing a "?" character won't be blacklisted as they're likely - // a route with query params (e.g. auth callbacks). - new RegExp('/[^/?]+\\.[^/]+$'), - ], - }), + new WorkboxWebpackPlugin.GenerateSW( + workboxConfig({ + clientsClaim: true, + exclude: [/\.map$/, /asset-manifest\.json$/], + importWorkboxFrom: 'cdn', + navigateFallback: publicUrl + '/index.html', + navigateFallbackBlacklist: [ + // Exclude URLs starting with /_, as they're likely an API call + new RegExp('^/_'), + // Exclude any URLs whose last part seems to be a file extension + // as they're likely a resource and not a SPA route. + // URLs containing a "?" character won't be blacklisted as they're likely + // a route with query params (e.g. auth callbacks). + new RegExp('/[^/?]+\\.[^/]+$'), + ], + }) + ), // TypeScript type checking useTypeScript && new ForkTsCheckerWebpackPlugin({