Skip to content

Commit

Permalink
feat(gatsby-plugin-offline): reload when missing resources and SW was…
Browse files Browse the repository at this point in the history
… updated + add "onServiceWorkerUpdateReady" API (#10432)
  • Loading branch information
vtenfys authored and pieh committed Jan 28, 2019
1 parent 7fee096 commit 4a01c6d
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 27 deletions.
4 changes: 2 additions & 2 deletions docs/docs/add-offline-support-with-a-service-worker.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ Note: Service worker registers only in production builds (`gatsby build`).

### Displaying a message when a service worker updates

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:
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:

```javascript:title=gatsby-browser.js
exports.onServiceWorkerUpdateFound = () => {
exports.onServiceWorkerUpdateReady = () => {
const answer = window.confirm(
`This application has been updated. ` +
`Reload to display the latest version?`
Expand Down
1 change: 0 additions & 1 deletion packages/gatsby-plugin-offline/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/*.js
!index.js
!sw-append.js
yarn.lock
9 changes: 6 additions & 3 deletions packages/gatsby-plugin-offline/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"dependencies": {
"@babel/runtime": "^7.0.0",
"cheerio": "^1.0.0-rc.2",
"cpx": "^1.5.0",
"idb-keyval": "^3.1.0",
"lodash": "^4.17.10",
"workbox-build": "^3.6.3"
Expand All @@ -30,12 +31,14 @@
"license": "MIT",
"main": "index.js",
"peerDependencies": {
"gatsby": ">=2.0.53"
"gatsby": "^2.0.100"
},
"repository": "https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-offline",
"scripts": {
"build": "babel src --out-dir . --ignore **/__tests__",
"build": "npm run build:src && npm run build:sw-append",
"build:src": "babel src --out-dir . --ignore **/__tests__,src/sw-append.js",
"build:sw-append": "cpx -v src/sw-append.js .",
"prepare": "cross-env NODE_ENV=production npm run build",
"watch": "babel -w src --out-dir . --ignore **/__tests__"
"watch": "npm run build:sw-append -- --watch & npm run build:src -- --watch"
}
}
11 changes: 11 additions & 0 deletions packages/gatsby-plugin-offline/src/gatsby-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ exports.onServiceWorkerActive = ({
getResourceURLsForPathname,
serviceWorker,
}) => {
// if the SW has just updated then reset whitelisted paths and don't cache
// stuff, since we're on the old revision until we navigate to another page
if (window.___swUpdated) {
serviceWorker.active.postMessage({ gatsbyApi: `resetWhitelist` })
return
}

// grab nodes from head of document
const nodes = document.querySelectorAll(`
head > script[src],
Expand Down Expand Up @@ -63,6 +70,10 @@ function whitelistPathname(pathname, includesPrefix) {
}

exports.onPostPrefetchPathname = ({ pathname }) => {
// do nothing if the SW has just updated, since we still have old pages in
// memory which we don't want to be whitelisted
if (window.___swUpdated) return

whitelistPathname(pathname, false)

// if SW is not installed, we need to record any prefetches
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,23 @@ const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => {
const cacheName = workbox.core.cacheNames.precache

return caches.match(offlineShell, { cacheName }).then(cachedResponse => {
if (!cachedResponse) {
return fetch(offlineShell).then(response => {
if (response.ok) {
return caches.open(cacheName).then(cache =>
// Clone is needed because put() consumes the response body.
cache.put(offlineShell, response.clone()).then(() => response)
)
} else {
return fetch(event.request)
}
})
}

return cachedResponse
if (cachedResponse) return cachedResponse

console.error(
`The offline shell (${offlineShell}) was not found ` +
`while attempting to serve a response for ${pathname}`
)

return fetch(offlineShell).then(response => {
if (response.ok) {
return caches.open(cacheName).then(cache =>
// Clone is needed because put() consumes the response body.
cache.put(offlineShell, response.clone()).then(() => response)
)
} else {
return fetch(event.request)
}
})
})
}

Expand Down
2 changes: 2 additions & 0 deletions packages/gatsby/cache-dir/ensure-resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ class EnsureResources extends React.Component {

render() {
if (!this.hasResources(this.state.pageResources) && isInitialRender) {
window.___failedResources = true

// prevent hydrating
throw new Error(`Missing resources for ${this.state.location.pathname}`)
}
Expand Down
5 changes: 1 addition & 4 deletions packages/gatsby/cache-dir/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,7 @@ const navigate = (to, options = {}) => {

// If we had a service worker update, no matter the path, reload window and
// reset the pathname whitelist
if (window.GATSBY_SW_UPDATED) {
const { controller } = navigator.serviceWorker
controller.postMessage({ gatsbyApi: `resetWhitelist` })

if (window.___swUpdated) {
window.location = pathname
return
}
Expand Down
11 changes: 10 additions & 1 deletion packages/gatsby/cache-dir/register-service-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,17 @@ if (
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.

// We set a flag so Gatsby Link knows to refresh the page on next navigation attempt
window.GATSBY_SW_UPDATED = true
window.___swUpdated = true
// We call the onServiceWorkerUpdateReady API so users can show update prompts.
apiRunner(`onServiceWorkerUpdateReady`, { serviceWorker: reg })

// If resources failed for the current page, reload.
if (window.___failedResources) {
console.log(`resources failed, SW updated - reloading`)
window.location.reload()
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a "Content is cached for offline use." message.
Expand Down
8 changes: 8 additions & 0 deletions packages/gatsby/src/utils/api-browser-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,14 @@ exports.onServiceWorkerInstalled = true
*/
exports.onServiceWorkerUpdateFound = true

/**
* Inform plugins when a service worker has been updated in the background
* and the page is ready to reload to apply changes.
* @param {object} $0
* @param {object} $0.serviceWorker The service worker instance.
*/
exports.onServiceWorkerUpdateReady = true

/**
* Inform plugins when a service worker has become active.
* @param {object} $0
Expand Down
33 changes: 31 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3665,7 +3665,7 @@ babel-register@^6.26.0, babel-register@^6.9.0:
mkdirp "^0.5.1"
source-map-support "^0.4.15"

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.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:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
Expand Down Expand Up @@ -4662,7 +4662,7 @@ cheerio@^1.0.0-rc.2:
lodash "^4.15.0"
parse5 "^3.0.1"

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

cpx@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/cpx/-/cpx-1.5.0.tgz#185be018511d87270dedccc293171e37655ab88f"
integrity sha1-GFvgGFEdhycN7czCkxceN2VauI8=
dependencies:
babel-runtime "^6.9.2"
chokidar "^1.6.0"
duplexer "^0.1.1"
glob "^7.0.5"
glob2base "^0.0.12"
minimatch "^3.0.2"
mkdirp "^0.5.1"
resolve "^1.1.7"
safe-buffer "^5.0.1"
shell-quote "^1.6.1"
subarg "^1.0.0"

crc-32@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208"
Expand Down Expand Up @@ -8023,6 +8040,11 @@ find-cache-dir@^2.0.0:
make-dir "^1.0.0"
pkg-dir "^3.0.0"

find-index@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4"
integrity sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=

find-npm-prefix@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf"
Expand Down Expand Up @@ -8649,6 +8671,13 @@ glob-to-regexp@^0.3.0:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=

glob2base@^0.0.12:
version "0.0.12"
resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56"
integrity sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=
dependencies:
find-index "^0.1.1"

glob@6.0.4:
version "6.0.4"
resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
Expand Down

0 comments on commit 4a01c6d

Please sign in to comment.