Skip to content

Commit f1e11a9

Browse files
jeffposnickianschmitz
authored andcommitted
Switch to the Workbox InjectManifest plugin (facebook#9205)
Co-authored-by: Ian Schmitz <[email protected]>
1 parent 37c832b commit f1e11a9

File tree

8 files changed

+103
-39
lines changed

8 files changed

+103
-39
lines changed

docusaurus/docs/making-a-progressive-web-app.md

+87-20
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,42 @@ title: Making a Progressive Web App
55

66
The production build has all the tools necessary to generate a first-class
77
[Progressive Web App](https://developers.google.com/web/progressive-web-apps/),
8-
but **the offline/cache-first behavior is opt-in only**. By default,
9-
the build process will generate a service worker file, but it will not be
10-
registered, so it will not take control of your production web app.
8+
but **the offline/cache-first behavior is opt-in only**.
9+
10+
Starting with Create React App 4, you can add a `src/service-worker.js` file to
11+
your project to use the built-in support for
12+
[Workbox](https://developers.google.com/web/tools/workbox/)'s
13+
[`InjectManifest`](https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-webpack-plugin.InjectManifest)
14+
plugin, which will
15+
[compile](https://developers.google.com/web/tools/workbox/guides/using-bundlers)
16+
your service worker and inject into it a list of URLs to
17+
[precache](https://developers.google.com/web/tools/workbox/guides/precache-files).
18+
19+
If you start a new project using one of the PWA [custom
20+
templates](https://create-react-app.dev/docs/custom-templates/), you'll get a
21+
`src/service-worker.js` file that serves as a good starting point for an
22+
offline-first service worker:
23+
24+
```sh
25+
npx create-react-app my-app --template cra-template-pwa
26+
```
27+
28+
The TypeScript equivalent is:
29+
30+
```sh
31+
npx create-react-app my-app --template cra-template-pwa-typescript
32+
```
33+
34+
If you know that you won't be using service workers, or if you'd prefer to use a
35+
different approach to creating your service worker, don't create a
36+
`src/service-worker.js` file. The `InjectManifest` plugin won't be run in that
37+
case.
1138

12-
In order to opt-in to the offline-first behavior, developers should look for the
13-
following in their [`src/index.js`](https://github.com/facebook/create-react-app/blob/master/packages/cra-template/template/src/index.js) file:
39+
In addition to creating your local `src/service-worker.js` file, it needs to be
40+
registered before it will be used. In order to opt-in to the offline-first
41+
behavior, developers should look for the following in their
42+
[`src/index.js`](https://github.com/facebook/create-react-app/blob/master/packages/cra-template/template/src/index.js)
43+
file:
1444

1545
```js
1646
// If you want your app to work offline and load faster, you can change
@@ -24,23 +54,59 @@ As the comment states, switching `serviceWorker.unregister()` to
2454

2555
## Why Opt-in?
2656

27-
Offline-first Progressive Web Apps are faster and more reliable than traditional web pages, and provide an engaging mobile experience:
57+
Offline-first Progressive Web Apps are faster and more reliable than traditional
58+
web pages, and provide an engaging mobile experience:
59+
60+
- All static site assets that are a part of your `webpack` build are cached so
61+
that your page loads fast on subsequent visits, regardless of network
62+
connectivity (such as 2G or 3G). Updates are downloaded in the background.
63+
- Your app will work regardless of network state, even if offline. This means
64+
your users will be able to use your app at 10,000 feet and on the subway.
65+
- On mobile devices, your app can be added directly to the user's home screen,
66+
app icon and all. This eliminates the need for the app store.
67+
68+
However, they [can make debugging deployments more
69+
challenging](https://github.com/facebook/create-react-app/issues/2398).
70+
71+
The
72+
[`workbox-webpack-plugin`](https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin)
73+
is integrated into production configuration, and it will take care of compiling
74+
a service worker file that will automatically precache all of your
75+
`webpack`-generated assets and keep them up to date as you deploy updates. The
76+
service worker will use a [cache-first
77+
strategy](https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#cache-falling-back-to-network)
78+
for handling all requests for `webpack`-generated assets, including [navigation
79+
requests](https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests)
80+
for your HTML, ensuring that your web app is consistently fast, even on a slow
81+
or unreliable network.
2882

29-
- All static site assets are cached so that your page loads fast on subsequent visits, regardless of network connectivity (such as 2G or 3G). Updates are downloaded in the background.
30-
- Your app will work regardless of network state, even if offline. This means your users will be able to use your app at 10,000 feet and on the subway.
31-
- On mobile devices, your app can be added directly to the user's home screen, app icon and all. This eliminates the need for the app store.
83+
Note: Resources that are not generated by `webpack`, such as static files that are
84+
copied over from your local
85+
[`public/` directory](https://github.com/facebook/create-react-app/blob/master/packages/cra-template/template/public/)
86+
or third-party resources, will not be precached. You can optionally set up Workbox
87+
[routes](https://developers.google.com/web/tools/workbox/guides/route-requests)
88+
to apply the runtime caching strategy of your choice to those resources.
89+
90+
## Customization
91+
92+
Starting with Create React App 4, you have full control over customizing the
93+
logic in this service worker, by creating your own `src/service-worker.js` file,
94+
or customizing the one added by the `cra-template-pwa` (or
95+
`cra-template-pwa-typescript`) template. You can use [additional
96+
modules](https://developers.google.com/web/tools/workbox/modules) from the
97+
Workbox project, add in a push notification library, or remove some of the
98+
default caching logic. The one requirement is that you keep `self.__WB_MANIFEST`
99+
somewhere in your file, as the Workbox compilation plugin checks for this value
100+
when generating a manifest of URLs to precache. If you would prefer not to use
101+
precaching, you can just assign `self.__WB_MANIFEST` to a variable that will be
102+
ignored, like:
32103

33-
However, they [can make debugging deployments more challenging](https://github.com/facebook/create-react-app/issues/2398) so, starting with Create React App 2, service workers are opt-in.
104+
```js
105+
// eslint-disable-next-line no-restricted-globals
106+
const ignored = self.__WB_MANIFEST;
34107

35-
The [`workbox-webpack-plugin`](https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin)
36-
is integrated into production configuration,
37-
and it will take care of generating a service worker file that will automatically
38-
precache all of your local assets and keep them up to date as you deploy updates.
39-
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)
40-
for handling all requests for local assets, including
41-
[navigation requests](https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests)
42-
for your HTML, ensuring that your web app is consistently fast, even on a slow
43-
or unreliable network.
108+
// Your custom service worker code goes here.
109+
```
44110

45111
## Offline-First Considerations
46112

@@ -88,7 +154,8 @@ following into account:
88154

89155
1. By default, the generated service worker file will not intercept or cache any
90156
cross-origin traffic, like HTTP [API requests](integrating-with-an-api-backend.md),
91-
images, or embeds loaded from a different domain.
157+
images, or embeds loaded from a different domain. Starting with Create
158+
React App 4, this can be customized, as explained above.
92159

93160
## Progressive Web App Metadata
94161

packages/cra-template-typescript/template/src/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import ReactDOM from 'react-dom';
33
import './index.css';
44
import App from './App';
5-
import * as serviceWorker from './serviceWorker';
5+
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
66
import reportWebVitals from './reportWebVitals';
77

88
ReactDOM.render(
@@ -15,7 +15,7 @@ ReactDOM.render(
1515
// If you want your app to work offline and load faster, you can change
1616
// unregister() to register() below. Note this comes with some pitfalls.
1717
// Learn more about service workers: https://cra.link/PWA
18-
serviceWorker.unregister();
18+
serviceWorkerRegistration.unregister();
1919

2020
// If you want to start measuring performance in your app, pass a function
2121
// to log results (for example: reportWebVitals(console.log))

packages/cra-template/template/src/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import ReactDOM from 'react-dom';
33
import './index.css';
44
import App from './App';
5-
import * as serviceWorker from './serviceWorker';
5+
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
66
import reportWebVitals from './reportWebVitals';
77

88
ReactDOM.render(
@@ -15,7 +15,7 @@ ReactDOM.render(
1515
// If you want your app to work offline and load faster, you can change
1616
// unregister() to register() below. Note this comes with some pitfalls.
1717
// Learn more about service workers: https://cra.link/PWA
18-
serviceWorker.unregister();
18+
serviceWorkerRegistration.unregister();
1919

2020
// If you want to start measuring performance in your app, pass a function
2121
// to log results (for example: reportWebVitals(console.log))

packages/react-scripts/config/paths.js

+3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ module.exports = {
7272
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
7373
proxySetup: resolveApp('src/setupProxy.js'),
7474
appNodeModules: resolveApp('node_modules'),
75+
swSrc: resolveModule(resolveApp, 'src/service-worker'),
7576
publicUrlOrPath,
7677
};
7778

@@ -94,6 +95,7 @@ module.exports = {
9495
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
9596
proxySetup: resolveApp('src/setupProxy.js'),
9697
appNodeModules: resolveApp('node_modules'),
98+
swSrc: resolveModule(resolveApp, 'src/service-worker'),
9799
publicUrlOrPath,
98100
// These properties only exist before ejecting:
99101
ownPath: resolveOwn('.'),
@@ -129,6 +131,7 @@ if (
129131
testsSetup: resolveModule(resolveOwn, `${templatePath}/src/setupTests`),
130132
proxySetup: resolveOwn(`${templatePath}/src/setupProxy.js`),
131133
appNodeModules: resolveOwn('node_modules'),
134+
swSrc: resolveModule(resolveOwn, `${templatePath}/src/service-worker`),
132135
publicUrlOrPath,
133136
// These properties only exist before ejecting:
134137
ownPath: resolveOwn('.'),

packages/react-scripts/config/webpack.config.js

+8-14
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ const imageInlineSizeLimit = parseInt(
6060
// Check if TypeScript is setup
6161
const useTypeScript = fs.existsSync(paths.appTsConfig);
6262

63+
// Get the path to the uncompiled service worker (if it exists).
64+
const swSrc = paths.swSrc;
65+
6366
// style files regexes
6467
const cssRegex = /\.css$/;
6568
const cssModuleRegex = /\.module\.css$/;
@@ -692,20 +695,11 @@ module.exports = function (webpackEnv) {
692695
// Generate a service worker script that will precache, and keep up to date,
693696
// the HTML & assets that are part of the webpack build.
694697
isEnvProduction &&
695-
new WorkboxWebpackPlugin.GenerateSW({
696-
clientsClaim: true,
697-
exclude: [/\.map$/, /asset-manifest\.json$/],
698-
importWorkboxFrom: 'cdn',
699-
navigateFallback: paths.publicUrlOrPath + 'index.html',
700-
navigateFallbackBlacklist: [
701-
// Exclude URLs starting with /_, as they're likely an API call
702-
new RegExp('^/_'),
703-
// Exclude any URLs whose last part seems to be a file extension
704-
// as they're likely a resource and not a SPA route.
705-
// URLs containing a "?" character won't be blacklisted as they're likely
706-
// a route with query params (e.g. auth callbacks).
707-
new RegExp('/[^/?]+\\.[^/]+$'),
708-
],
698+
fs.existsSync(swSrc) &&
699+
new WorkboxWebpackPlugin.InjectManifest({
700+
swSrc,
701+
dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
702+
exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],
709703
}),
710704
// TypeScript type checking
711705
useTypeScript &&

packages/react-scripts/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
"webpack": "4.43.0",
8383
"webpack-dev-server": "3.11.0",
8484
"webpack-manifest-plugin": "2.2.0",
85-
"workbox-webpack-plugin": "4.3.1"
85+
"workbox-webpack-plugin": "5.1.3"
8686
},
8787
"devDependencies": {
8888
"react": "^16.12.0",

0 commit comments

Comments
 (0)