-
Notifications
You must be signed in to change notification settings - Fork 3
PWA functionality for create-react-app #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
8289386
8ec99b6
1fe6f55
e8ae98d
071d996
f840b4d
9ffa9e4
c7ba130
96ebb75
ca7fb22
6c85568
75088ab
434e858
411347f
c9bc6ce
915b130
ce0d6ee
9df3104
745d341
fc49946
1d5a277
9c33f60
6d22a78
b0bc46e
075e729
5e65f0d
c8cbbd0
1fc1d82
e9493a2
41632fb
bfed215
2835105
2dc418b
21d14bb
a681e91
a9fb906
bee4ece
dd9ec7b
1aa4b2b
2a8535b
d945370
a82896c
21fe19a
7be0f4d
646690b
92a0680
67d0d49
bec009c
577c4e8
e14e003
0ef9e80
09cfcde
c3240a1
1c0851d
d6a83aa
41d1469
dd801e2
c8d9c47
53db95a
8d41328
925ab72
5155797
b609ac9
dbf17fd
3289c32
2288ddf
6876c40
f3d8fff
e1aaf39
f68cc67
253c1e0
2f6fac9
fbae44a
ba5da93
e1e28d9
68e9bb9
432ba82
d0695f7
a1858c7
a3a223a
2d93ae1
715968e
c51a611
3509dcd
7c899fc
2b824d8
bf948bf
15e1ec2
ee3b788
a85ae1d
10a8dc6
342867e
1a838dc
60ba9f2
af6a0ff
43139bc
404c354
45d1d24
db64278
c7a9dae
1cdb4cd
4e3ede4
59cab8f
b88d665
72695a1
b421ed9
8951fbe
443ca23
3fe8289
19a4672
4ec5af3
ae61bf6
9d8096e
23f85d3
d07accb
5414cff
01c3597
ed9eeeb
13f26e3
86d590d
0640a20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1048,7 +1048,82 @@ Learn more about React Storybook: | |
|
||
## Making a Progressive Web App | ||
|
||
You can turn your React app into a [Progressive Web App](https://developers.google.com/web/progressive-web-apps/) by following the steps in [this repository](https://github.com/jeffposnick/create-react-pwa). | ||
By default, the production build is a fully functional, offline-first | ||
[Progressive Web App](https://developers.google.com/web/progressive-web-apps/). | ||
|
||
The [`sw-precache-webpack-plugin`](https://github.com/goldhand/sw-precache-webpack-plugin) | ||
is integrated into [`webpack.config.prod.js`](../config/webpack.config.prod.js), | ||
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) | ||
for handling all requests for local assets, including the initial HTML, ensuring | ||
that you web app is reliably fast, even on a slow or unreliable network. | ||
|
||
It includes a [web app manifest](https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/), | ||
located at [`public/manifest.json`](public/manifest.json), that you might want | ||
to customize with metadata specific to your web application, such as its name | ||
and branding colors. | ||
|
||
If you would prefer not to enable service workers prior to your initial | ||
production deployment, then remove the call to `serviceWorkerRegistration.register()` | ||
from [`src/index.js`](src/index.js). | ||
|
||
If you had previously enabled service workers in your production deployment and | ||
have decided that you would like to disable them for all your existing users, | ||
you can swap out the call to `serviceWorkerRegistration.register()` in | ||
[`src/index.js`](src/index.js) with a call to `serviceWorkerRegistration.unregister()`. | ||
After the user visits a page that has `serviceWorkerRegistration.unregister()`, | ||
the service worker will be uninstalled. | ||
|
||
### Offline-First Considerations | ||
|
||
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 currently supported](https://jakearchibald.github.io/isserviceworkerready/) | ||
in all web browsers. Service worker registration [won't be attempted](src/register-service-worker.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 | ||
frustration when previously cached assets are used and do not include the latest | ||
changes you've made locally. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggest adding instructions for testing locally (incase they want to despite your warning. I have no doubt some people will). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Merged. |
||
1. If possible,configure your production environment to serve the generated | ||
`service-worker.js` [with HTTP caching disabled](http://stackoverflow.com/questions/38843970/service-worker-javascript-update-frequency-every-24-hours). | ||
If that's not possible—[GitHub Pages](#github-pages), for instance, does not | ||
allow you to change the default 10 minute HTTP cache lifetime—then be aware | ||
that if you visit your production site, and then revisit again before | ||
`service-worker.js` has expired from your HTTP cache, you'll continue to get | ||
the previously cached assets from the service worker. If you have an immediate | ||
need to view your updated production deployment, performing a shift-refresh | ||
will temporarily disable the service worker and retrieve all assets from the | ||
network. | ||
|
||
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/register-service-worker.js`](src/register-service-worker.js), which | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in PR #3 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. merged into #2 |
||
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. If you would like to use a | ||
runtime caching strategy for those requests, you can [`eject`](#npm-run-eject) | ||
and then configure the | ||
[`runtimeCaching`](https://github.com/GoogleChrome/sw-precache#runtimecaching-arrayobject) | ||
option in the `SWPrecachePlugin` section of | ||
[`webpack.config.prod.js`](../config/webpack.config.prod.js). | ||
|
||
## Deployment | ||
|
||
|
@@ -1096,6 +1171,15 @@ This is because when there is a fresh page load for a `/todos/42`, the server lo | |
|
||
Now requests to `/todos/42` will be handled correctly both in development and in production. | ||
|
||
On a production build, and in a browser that supports [service workers](https://developers.google.com/web/fundamentals/getting-started/primers/service-workers), | ||
the service worker will automatically handle all navigation requests, like for | ||
`/todos/42`, by serving the cached copy of your `index.html`. This | ||
service worker navigation routing can be configured or disabled by | ||
[`eject`ing](#npm-run-eject) and then modifying the | ||
[`navigateFallback`](https://github.com/GoogleChrome/sw-precache#navigatefallback-string) | ||
and [`navigateFallbackWhitelist`](https://github.com/GoogleChrome/sw-precache#navigatefallbackwhitelist-arrayregexp) | ||
options of the `SWPreachePlugin` [configuration](../config/webpack.config.prod.js). | ||
|
||
### Building for Relative Paths | ||
|
||
By default, Create React App produces a build assuming your app is hosted at the server root.<br> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"short_name": "React App", | ||
"name": "React App", | ||
"icons": [ | ||
{ | ||
"src": "favicon.ico", | ||
"sizes": "192x192", | ||
"type": "image/png" | ||
} | ||
], | ||
"start_url": "./", | ||
"display": "standalone" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,12 @@ | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import App from './App'; | ||
import * as serviceWorkerRegistration from './service-worker-registration'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you are importing both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just noting that these proposed changes are not in any pr (everything else is though) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed. |
||
import './index.css'; | ||
|
||
ReactDOM.render( | ||
<App />, | ||
document.getElementById('root') | ||
); | ||
|
||
serviceWorkerRegistration.register(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
export function register() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed. |
||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without an accompanying unit test (which would likely require some heavy-duty mocking), the code including and past this line has a negative effect on my project's coverage report. I left a comment on an upstream issue (facebook#1299 (comment)) regarding having the ability for Jest to ignore files such as this. EDIT: There is another issue, facebook#1455, that directly addresses this concern. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah... I don't know much about Jest, and have yet to find a good way to create a mock environment for testing service worker-specific code outside of a real browser. I'm hoping that some resolution would come out of those issues you reference. Is there anything that you'd suggest adding to this PR to work around it in the meantime? |
||
window.addEventListener('load', () => { | ||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; | ||
navigator.serviceWorker.register(swUrl).then(registration => { | ||
registration.onupdatefound = () => { | ||
const installingWorker = registration.installing; | ||
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.'); | ||
} else { | ||
// At this point, everything has been precached. | ||
// It's the perfect time to display a | ||
// "Content is cached for offline use." message. | ||
console.log('Content is cached for offline use.'); | ||
} | ||
} | ||
}; | ||
}; | ||
}).catch(error => { | ||
console.error('Error during service worker registration:', error); | ||
}); | ||
}); | ||
} | ||
} | ||
|
||
export function unregister() { | ||
if ('serviceWorker' in navigator) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check for production environment ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm providing I'm thinking that if someone calls it, then they really want any registered service workers to be removed, even if they don't have The code is also effectively a no-op if there is no service worker registered ( |
||
navigator.serviceWorker.ready.then(function(registration) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change the callback function to arrow function syntax, for the sake of consistency with the rest of the file. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed. |
||
registration.unregister(); | ||
}); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe
src/register-service-worker.js
should besrc/service-worker-registration.js
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in PR #3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merged @ianschmitz commit from pr #3 into pr #2 to avoid merge conflicts (I want to suggest other changes to the README)