diff --git a/packages/gatsby-plugin-offline/src/gatsby-ssr.js b/packages/gatsby-plugin-offline/src/gatsby-ssr.js index 10e97c5a28e1b..b594d165cfae3 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-ssr.js +++ b/packages/gatsby-plugin-offline/src/gatsby-ssr.js @@ -30,12 +30,10 @@ export const onRenderBody = ({ pathname, setHeadComponents }) => { setHeadComponents([ , ]) } diff --git a/packages/gatsby-plugin-offline/src/sw-append.js b/packages/gatsby-plugin-offline/src/sw-append.js index c6dc3865777e4..283ca4de614a4 100644 --- a/packages/gatsby-plugin-offline/src/sw-append.js +++ b/packages/gatsby-plugin-offline/src/sw-append.js @@ -3,13 +3,78 @@ importScripts(`idb-keyval-iife.min.js`) const { NavigationRoute } = workbox.routing + +let lastNavigationRequest = null let offlineShellEnabled = true +// prefer standard object syntax to support more browsers +const MessageAPI = { + setPathResources: (event, { path, resources }) => { + event.waitUntil(idbKeyval.set(`resources:${path}`, resources)) + }, + + clearPathResources: event => { + event.waitUntil(idbKeyval.clear()) + }, + + enableOfflineShell: () => { + offlineShellEnabled = true + }, + + disableOfflineShell: () => { + offlineShellEnabled = false + }, +} + +self.addEventListener(`message`, event => { + const { gatsbyApi: api } = event.data + if (api) MessageAPI[api](event, event.data) +}) + +function handleAPIRequest({ event }) { + const { pathname } = new URL(event.request.url) + + const params = pathname.match(/:(.+)/)[1] + const data = {} + + if (params.indexOf(`=`) !== -1) { + params.split(`&`).forEach(param => { + const [key, val] = param.split(`=`) + data[key] = val + }) + } else { + data.api = params + } + + if (MessageAPI[data.api] !== undefined) { + MessageAPI[data.api]() + } + + if (!data.redirect) { + return new Response() + } + + return new Response(null, { + status: 302, + headers: { + Location: lastNavigationRequest, + }, + }) +} + const navigationRoute = new NavigationRoute(async ({ event }) => { + // handle API requests separately to normal navigation requests, so do this + // check first + if (event.request.url.match(/\/.gatsby-plugin-offline:.+/)) { + return handleAPIRequest({ event }) + } + if (!offlineShellEnabled) { return await fetch(event.request) } + lastNavigationRequest = event.request.url + let { pathname } = new URL(event.request.url) pathname = pathname.replace(new RegExp(`^%pathPrefix%`), ``) @@ -36,35 +101,5 @@ const navigationRoute = new NavigationRoute(async ({ event }) => { workbox.routing.registerRoute(navigationRoute) -// prefer standard object syntax to support more browsers -const MessageAPI = { - setPathResources: (event, { path, resources }) => { - event.waitUntil(idbKeyval.set(`resources:${path}`, resources)) - }, - - clearPathResources: event => { - event.waitUntil(idbKeyval.clear()) - }, - - enableOfflineShell: () => { - offlineShellEnabled = true - }, - - disableOfflineShell: () => { - offlineShellEnabled = false - }, -} - -self.addEventListener(`message`, event => { - const { gatsbyApi: api } = event.data - if (api) MessageAPI[api](event, event.data) -}) - -workbox.routing.registerRoute(/\/.gatsby-plugin-offline:.+/, ({ event }) => { - const { pathname } = new URL(event.request.url) - - const api = pathname.match(/:(.+)/)[1] - MessageAPI[api]() - - return new Response() -}) +// this route is used when performing a non-navigation request (e.g. fetch) +workbox.routing.registerRoute(/\/.gatsby-plugin-offline:.+/, handleAPIRequest)