Skip to content

Commit 4a01c6d

Browse files
vtenfyspieh
authored andcommitted
feat(gatsby-plugin-offline): reload when missing resources and SW was updated + add "onServiceWorkerUpdateReady" API (#10432)
1 parent 7fee096 commit 4a01c6d

File tree

10 files changed

+88
-27
lines changed

10 files changed

+88
-27
lines changed

docs/docs/add-offline-support-with-a-service-worker.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ Note: Service worker registers only in production builds (`gatsby build`).
4545

4646
### Displaying a message when a service worker updates
4747

48-
To display a custom message once your service worker finds an update, you can use the [`onServiceWorkerUpdateFound`](/docs/browser-apis/#onServiceWorkerUpdateFound) browser API in your `gatsby-browser.js` file. The following code will display a confirm prompt asking the user whether they would like to refresh the page when an update is found:
48+
To display a custom message once your service worker finds an update, you can use the [`onServiceWorkerUpdateReady`](/docs/browser-apis/#onServiceWorkerUpdateReady) browser API in your `gatsby-browser.js` file. The following code will display a confirm prompt asking the user whether they would like to refresh the page when an update is found:
4949

5050
```javascript:title=gatsby-browser.js
51-
exports.onServiceWorkerUpdateFound = () => {
51+
exports.onServiceWorkerUpdateReady = () => {
5252
const answer = window.confirm(
5353
`This application has been updated. ` +
5454
`Reload to display the latest version?`
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
/*.js
22
!index.js
3-
!sw-append.js
43
yarn.lock

packages/gatsby-plugin-offline/package.json

+6-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"dependencies": {
1010
"@babel/runtime": "^7.0.0",
1111
"cheerio": "^1.0.0-rc.2",
12+
"cpx": "^1.5.0",
1213
"idb-keyval": "^3.1.0",
1314
"lodash": "^4.17.10",
1415
"workbox-build": "^3.6.3"
@@ -30,12 +31,14 @@
3031
"license": "MIT",
3132
"main": "index.js",
3233
"peerDependencies": {
33-
"gatsby": ">=2.0.53"
34+
"gatsby": "^2.0.100"
3435
},
3536
"repository": "https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-offline",
3637
"scripts": {
37-
"build": "babel src --out-dir . --ignore **/__tests__",
38+
"build": "npm run build:src && npm run build:sw-append",
39+
"build:src": "babel src --out-dir . --ignore **/__tests__,src/sw-append.js",
40+
"build:sw-append": "cpx -v src/sw-append.js .",
3841
"prepare": "cross-env NODE_ENV=production npm run build",
39-
"watch": "babel -w src --out-dir . --ignore **/__tests__"
42+
"watch": "npm run build:sw-append -- --watch & npm run build:src -- --watch"
4043
}
4144
}

packages/gatsby-plugin-offline/src/gatsby-browser.js

+11
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ exports.onServiceWorkerActive = ({
77
getResourceURLsForPathname,
88
serviceWorker,
99
}) => {
10+
// if the SW has just updated then reset whitelisted paths and don't cache
11+
// stuff, since we're on the old revision until we navigate to another page
12+
if (window.___swUpdated) {
13+
serviceWorker.active.postMessage({ gatsbyApi: `resetWhitelist` })
14+
return
15+
}
16+
1017
// grab nodes from head of document
1118
const nodes = document.querySelectorAll(`
1219
head > script[src],
@@ -63,6 +70,10 @@ function whitelistPathname(pathname, includesPrefix) {
6370
}
6471

6572
exports.onPostPrefetchPathname = ({ pathname }) => {
73+
// do nothing if the SW has just updated, since we still have old pages in
74+
// memory which we don't want to be whitelisted
75+
if (window.___swUpdated) return
76+
6677
whitelistPathname(pathname, false)
6778

6879
// if SW is not installed, we need to record any prefetches

packages/gatsby-plugin-offline/sw-append.js renamed to packages/gatsby-plugin-offline/src/sw-append.js

+17-14
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,23 @@ const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => {
1313
const cacheName = workbox.core.cacheNames.precache
1414

1515
return caches.match(offlineShell, { cacheName }).then(cachedResponse => {
16-
if (!cachedResponse) {
17-
return fetch(offlineShell).then(response => {
18-
if (response.ok) {
19-
return caches.open(cacheName).then(cache =>
20-
// Clone is needed because put() consumes the response body.
21-
cache.put(offlineShell, response.clone()).then(() => response)
22-
)
23-
} else {
24-
return fetch(event.request)
25-
}
26-
})
27-
}
28-
29-
return cachedResponse
16+
if (cachedResponse) return cachedResponse
17+
18+
console.error(
19+
`The offline shell (${offlineShell}) was not found ` +
20+
`while attempting to serve a response for ${pathname}`
21+
)
22+
23+
return fetch(offlineShell).then(response => {
24+
if (response.ok) {
25+
return caches.open(cacheName).then(cache =>
26+
// Clone is needed because put() consumes the response body.
27+
cache.put(offlineShell, response.clone()).then(() => response)
28+
)
29+
} else {
30+
return fetch(event.request)
31+
}
32+
})
3033
})
3134
}
3235

packages/gatsby/cache-dir/ensure-resources.js

+2
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ class EnsureResources extends React.Component {
129129

130130
render() {
131131
if (!this.hasResources(this.state.pageResources) && isInitialRender) {
132+
window.___failedResources = true
133+
132134
// prevent hydrating
133135
throw new Error(`Missing resources for ${this.state.location.pathname}`)
134136
}

packages/gatsby/cache-dir/navigation.js

+1-4
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,7 @@ const navigate = (to, options = {}) => {
6767

6868
// If we had a service worker update, no matter the path, reload window and
6969
// reset the pathname whitelist
70-
if (window.GATSBY_SW_UPDATED) {
71-
const { controller } = navigator.serviceWorker
72-
controller.postMessage({ gatsbyApi: `resetWhitelist` })
73-
70+
if (window.___swUpdated) {
7471
window.location = pathname
7572
return
7673
}

packages/gatsby/cache-dir/register-service-worker.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,17 @@ if (
2323
if (navigator.serviceWorker.controller) {
2424
// At this point, the old content will have been purged and the fresh content will
2525
// have been added to the cache.
26+
2627
// We set a flag so Gatsby Link knows to refresh the page on next navigation attempt
27-
window.GATSBY_SW_UPDATED = true
28+
window.___swUpdated = true
29+
// We call the onServiceWorkerUpdateReady API so users can show update prompts.
30+
apiRunner(`onServiceWorkerUpdateReady`, { serviceWorker: reg })
31+
32+
// If resources failed for the current page, reload.
33+
if (window.___failedResources) {
34+
console.log(`resources failed, SW updated - reloading`)
35+
window.location.reload()
36+
}
2837
} else {
2938
// At this point, everything has been precached.
3039
// It's the perfect time to display a "Content is cached for offline use." message.

packages/gatsby/src/utils/api-browser-docs.js

+8
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,14 @@ exports.onServiceWorkerInstalled = true
211211
*/
212212
exports.onServiceWorkerUpdateFound = true
213213

214+
/**
215+
* Inform plugins when a service worker has been updated in the background
216+
* and the page is ready to reload to apply changes.
217+
* @param {object} $0
218+
* @param {object} $0.serviceWorker The service worker instance.
219+
*/
220+
exports.onServiceWorkerUpdateReady = true
221+
214222
/**
215223
* Inform plugins when a service worker has become active.
216224
* @param {object} $0

yarn.lock

+31-2
Original file line numberDiff line numberDiff line change
@@ -3665,7 +3665,7 @@ babel-register@^6.26.0, babel-register@^6.9.0:
36653665
mkdirp "^0.5.1"
36663666
source-map-support "^0.4.15"
36673667

3668-
babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
3668+
babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0, babel-runtime@^6.9.2:
36693669
version "6.26.0"
36703670
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
36713671
integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
@@ -4662,7 +4662,7 @@ cheerio@^1.0.0-rc.2:
46624662
lodash "^4.15.0"
46634663
parse5 "^3.0.1"
46644664

4665-
chokidar@^1.4.2, chokidar@^1.7.0:
4665+
chokidar@^1.4.2, chokidar@^1.6.0, chokidar@^1.7.0:
46664666
version "1.7.0"
46674667
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
46684668
integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=
@@ -5487,6 +5487,23 @@ cosmiconfig@^5.0.0, cosmiconfig@^5.0.2, cosmiconfig@^5.0.5, cosmiconfig@^5.0.6:
54875487
js-yaml "^3.9.0"
54885488
parse-json "^4.0.0"
54895489

5490+
cpx@^1.5.0:
5491+
version "1.5.0"
5492+
resolved "https://registry.yarnpkg.com/cpx/-/cpx-1.5.0.tgz#185be018511d87270dedccc293171e37655ab88f"
5493+
integrity sha1-GFvgGFEdhycN7czCkxceN2VauI8=
5494+
dependencies:
5495+
babel-runtime "^6.9.2"
5496+
chokidar "^1.6.0"
5497+
duplexer "^0.1.1"
5498+
glob "^7.0.5"
5499+
glob2base "^0.0.12"
5500+
minimatch "^3.0.2"
5501+
mkdirp "^0.5.1"
5502+
resolve "^1.1.7"
5503+
safe-buffer "^5.0.1"
5504+
shell-quote "^1.6.1"
5505+
subarg "^1.0.0"
5506+
54905507
crc-32@~1.2.0:
54915508
version "1.2.0"
54925509
resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208"
@@ -8023,6 +8040,11 @@ find-cache-dir@^2.0.0:
80238040
make-dir "^1.0.0"
80248041
pkg-dir "^3.0.0"
80258042

8043+
find-index@^0.1.1:
8044+
version "0.1.1"
8045+
resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4"
8046+
integrity sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=
8047+
80268048
find-npm-prefix@^1.0.2:
80278049
version "1.0.2"
80288050
resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf"
@@ -8649,6 +8671,13 @@ glob-to-regexp@^0.3.0:
86498671
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
86508672
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
86518673

8674+
glob2base@^0.0.12:
8675+
version "0.0.12"
8676+
resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56"
8677+
integrity sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=
8678+
dependencies:
8679+
find-index "^0.1.1"
8680+
86528681
86538682
version "6.0.4"
86548683
resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"

0 commit comments

Comments
 (0)