From 6f53bb11a764526b9e769fbf30b7081aa7fa4b56 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 5 Nov 2018 22:09:45 +0000 Subject: [PATCH 01/21] Remove all no-cache code --- packages/gatsby/cache-dir/ensure-resources.js | 8 +- .../gatsby/cache-dir/load-directly-or-404.js | 69 -------------- packages/gatsby/cache-dir/navigation.js | 14 ++- packages/gatsby/cache-dir/production-app.js | 90 ++++++++----------- 4 files changed, 42 insertions(+), 139 deletions(-) delete mode 100644 packages/gatsby/cache-dir/load-directly-or-404.js diff --git a/packages/gatsby/cache-dir/ensure-resources.js b/packages/gatsby/cache-dir/ensure-resources.js index c94146cd181c0..95cc5620110af 100644 --- a/packages/gatsby/cache-dir/ensure-resources.js +++ b/packages/gatsby/cache-dir/ensure-resources.js @@ -2,7 +2,6 @@ import React from "react" import PropTypes from "prop-types" import loader from "./loader" import shallowCompare from "shallow-compare" -import { getRedirectUrl } from "./load-directly-or-404" // Pass pathname in as prop. // component will try fetching resources. If they exist, @@ -94,16 +93,11 @@ class EnsureResources extends React.Component { } render() { + // This should only occur if there's no custom 404 page if ( process.env.NODE_ENV === `production` && !(this.state.pageResources && this.state.pageResources.json) ) { - // This should only occur if there's no custom 404 page - const url = getRedirectUrl(this.state.location.href) - if (url) { - window.location.replace(url) - } - return null } diff --git a/packages/gatsby/cache-dir/load-directly-or-404.js b/packages/gatsby/cache-dir/load-directly-or-404.js deleted file mode 100644 index f195385ea27f3..0000000000000 --- a/packages/gatsby/cache-dir/load-directly-or-404.js +++ /dev/null @@ -1,69 +0,0 @@ -export function getRedirectUrl(path) { - const url = new URL(path, window.location.origin) - - // This should never happen, but check just in case - otherwise, there would - // be an infinite redirect loop - if (url.search.match(/\?(.*&)?no-cache=1(&|$)/)) { - console.error( - `Found no-cache=1 while attempting to load a page directly; ` + - `this is likely due to a bug in Gatsby, or a misconfiguration in your project.` - ) - return false - } - - // Append the appropriate query to the URL. - if (url.search) { - url.search += `&no-cache=1` - } else { - url.search = `?no-cache=1` - } - - return url -} - -/** - * When other parts of the code can't find resources for a page, they load the 404 page's - * resources (if it exists) and then pass them here. This module then does the following: - * 1. Checks if 404 pages resources exist. If not, just navigate directly to the desired URL - * to show whatever server 404 page exists. - * 2. Try fetching the desired page to see if it exists on the server but we - * were just prevented from seeing it due to loading the site from a SW. If this is the case, - * trigger a hard reload to grab that page from the server. - * 3. If the page doesn't exist, show the normal 404 page component. - * 4. If the fetch failed (generally meaning we're offline), then navigate anyways to show - * either the browser's offline page or whatever the server error is. - */ -export default function(resources, path, replaceOnSuccess = false) { - return new Promise((resolve, reject) => { - const url = getRedirectUrl(path) - if (!url) return reject(url) - - // Always navigate directly if a custom 404 page doesn't exist. - if (!resources) { - window.location = url - } else { - // Now test if the page is available directly - fetch(url.href) - .then(response => { - if (response.status !== 404) { - // Redirect there if there isn't a 404. If a different HTTP - // error occurs, the appropriate error message will be - // displayed after loading the page directly. - if (replaceOnSuccess) { - window.location.replace(url) - } else { - window.location = url - } - } else { - // If a 404 occurs, show the custom 404 page. - resolve() - } - }) - .catch(() => { - // If an error occurs (usually when offline), navigate to the - // page anyway to show the browser's proper offline error page - window.location = url - }) - } - }) -} diff --git a/packages/gatsby/cache-dir/navigation.js b/packages/gatsby/cache-dir/navigation.js index fadd1c7685076..ad4fecb1898e1 100644 --- a/packages/gatsby/cache-dir/navigation.js +++ b/packages/gatsby/cache-dir/navigation.js @@ -1,12 +1,11 @@ import React from "react" import PropTypes from "prop-types" -import loader, { setApiRunnerForLoader } from "./loader" +import loader from "./loader" import redirects from "./redirects.json" import { apiRunner } from "./api-runner-browser" import emitter from "./emitter" import { navigate as reachNavigate } from "@reach/router" import parsePath from "./parse-path" -import loadDirectlyOr404 from "./load-directly-or-404" // Convert to a map for faster lookup in maybeRedirect() const redirectMap = redirects.reduce((map, redirect) => { @@ -82,14 +81,11 @@ const navigate = (to, options = {}) => { }, 1000) loader.getResourcesForPathname(pathname).then(pageResources => { - if ( - (!pageResources || pageResources.page.path === `/404.html`) && - process.env.NODE_ENV === `production` - ) { - clearTimeout(timeoutId) - loadDirectlyOr404(pageResources, to).then(() => + if (!pageResources && process.env.NODE_ENV === `production`) { + loader.getResourcesForPathname(`/404.html`).then(() => { + clearTimeout(timeoutId) reachNavigate(to, options) - ) + }) } else { reachNavigate(to, options) clearTimeout(timeoutId) diff --git a/packages/gatsby/cache-dir/production-app.js b/packages/gatsby/cache-dir/production-app.js index 9c4a861d9bd8b..a3d51f0579a20 100644 --- a/packages/gatsby/cache-dir/production-app.js +++ b/packages/gatsby/cache-dir/production-app.js @@ -15,7 +15,6 @@ window.___emitter = emitter import PageRenderer from "./page-renderer" import asyncRequires from "./async-requires" import loader, { setApiRunnerForLoader } from "./loader" -import loadDirectlyOr404 from "./load-directly-or-404" import EnsureResources from "./ensure-resources" window.asyncRequires = asyncRequires @@ -67,18 +66,14 @@ apiRunnerAsync(`onClientEntry`).then(() => { if ( // Make sure the window.page object is defined page && - // The canonical path doesn't match the actual path (i.e. the address bar) __PATH_PREFIX__ + page.path !== browserLoc.pathname && - // ...and if matchPage is specified, it also doesn't match the actual path (!page.matchPath || !match(__PATH_PREFIX__ + page.matchPath, browserLoc.pathname)) && - // Ignore 404 pages, since we want to keep the same URL page.path !== `/404.html` && !page.path.match(/^\/404\/?$/) && - // Also ignore the offline shell (since when using the offline plugin, all // pages have this canonical path) !page.path.match(/^\/offline-plugin-app-shell-fallback\/?$/) @@ -89,56 +84,43 @@ apiRunnerAsync(`onClientEntry`).then(() => { ) } - loader - .getResourcesForPathname(browserLoc.pathname) - .then(resources => { - if (!resources || resources.page.path === `/404.html`) { - return loadDirectlyOr404( - resources, - browserLoc.pathname + browserLoc.search + browserLoc.hash, - true - ) - } - - return null - }) - .then(() => { - const Root = () => - createElement( - Router, - { - basepath: __PATH_PREFIX__, - }, - createElement(RouteHandler, { path: `/*` }) - ) + loader.getResourcesForPathname(browserLoc.pathname).then(() => { + const Root = () => + createElement( + Router, + { + basepath: __PATH_PREFIX__, + }, + createElement(RouteHandler, { path: `/*` }) + ) - const WrappedRoot = apiRunner( - `wrapRootElement`, - { element: }, - , - ({ result }) => { - return { element: result } + const WrappedRoot = apiRunner( + `wrapRootElement`, + { element: }, + , + ({ result }) => { + return { element: result } + } + ).pop() + + let NewRoot = () => WrappedRoot + + const renderer = apiRunner( + `replaceHydrateFunction`, + undefined, + ReactDOM.hydrate + )[0] + + domReady(() => { + renderer( + , + typeof window !== `undefined` + ? document.getElementById(`___gatsby`) + : void 0, + () => { + apiRunner(`onInitialClientRender`) } - ).pop() - - let NewRoot = () => WrappedRoot - - const renderer = apiRunner( - `replaceHydrateFunction`, - undefined, - ReactDOM.hydrate - )[0] - - domReady(() => { - renderer( - , - typeof window !== `undefined` - ? document.getElementById(`___gatsby`) - : void 0, - () => { - apiRunner(`onInitialClientRender`) - } - ) - }) + ) }) + }) }) From 41a932afd978eb1060370ebc37020f30293a5a9f Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 5 Nov 2018 22:13:47 +0000 Subject: [PATCH 02/21] Remove references to no-cache in offline plugin --- packages/gatsby-plugin-offline/src/gatsby-node.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/gatsby-plugin-offline/src/gatsby-node.js b/packages/gatsby-plugin-offline/src/gatsby-node.js index a9f4419e93d21..c9000f45c9bae 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-node.js +++ b/packages/gatsby-plugin-offline/src/gatsby-node.js @@ -80,16 +80,14 @@ exports.onPostBuild = (args, pluginOptions) => { "/": `${pathPrefix}/`, }, navigateFallback: `${pathPrefix}/offline-plugin-app-shell-fallback/index.html`, - // Only match URLs without extensions or the query `no-cache=1`. + // Only match URLs without extensions. // So example.com/about/ will pass but - // example.com/about/?no-cache=1 and // example.com/cheeseburger.jpg will not. // We only want the service worker to handle our "clean" // URLs and not any files hosted on the site. // // Regex based on http://stackoverflow.com/a/18017805 navigateFallbackWhitelist: [/^([^.?]*|[^?]*\.([^.?]{5,}|html))(\?.*)?$/], - navigateFallbackBlacklist: [/\?(.+&)?no-cache=1$/], cacheId: `gatsby-plugin-offline`, // Don't cache-bust JS or CSS files, and anything in the static directory dontCacheBustUrlsMatching: /(.*\.js$|.*\.css$|\/static\/)/, From a1cecf43f85567b1a12186a85d0d5c10767b7014 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 12 Nov 2018 16:07:34 +0000 Subject: [PATCH 03/21] Initial work on hybrid navigation handler --- .../src/gatsby-browser.js | 25 ++++++- .../gatsby-plugin-offline/src/gatsby-node.js | 20 ++---- .../gatsby-plugin-offline/src/sw-append.js | 67 +++++++++++++++++-- 3 files changed, 90 insertions(+), 22 deletions(-) diff --git a/packages/gatsby-plugin-offline/src/gatsby-browser.js b/packages/gatsby-plugin-offline/src/gatsby-browser.js index 318efddceac57..f8df48c8e7033 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-browser.js +++ b/packages/gatsby-plugin-offline/src/gatsby-browser.js @@ -2,7 +2,10 @@ exports.registerServiceWorker = () => true let swNotInstalled = true const prefetchedPathnames = [] +const whitelistedPathnames = [] +// TODO - check if swNotInstalled is true when the SW is actually installed +// (causing duplicate cache storage) exports.onPostPrefetchPathname = ({ pathname }) => { // if SW is not installed, we need to record any prefetches // that happen so we can then add them to SW cache once installed @@ -41,7 +44,27 @@ exports.onServiceWorkerActive = ({ ) serviceWorker.active.postMessage({ - api: `gatsby-runtime-cache`, + gatsbyApi: `runtimeCache`, resources: [...resources, ...prefetchedResources], }) + serviceWorker.active.postMessage({ + gatsbyApi: `whitelistPathnames`, + pathnames: whitelistedPathnames, + }) +} + +exports.onRouteUpdate = ({ location }) => { + if (`serviceWorker` in navigator) { + const { serviceWorker } = navigator + const pathname = location.pathname + location.search + + if (serviceWorker.controller !== null) { + serviceWorker.controller.postMessage({ + gatsbyApi: `whitelistPathnames`, + pathnames: [pathname], + }) + } else { + whitelistedPathnames.push(pathname) + } + } } diff --git a/packages/gatsby-plugin-offline/src/gatsby-node.js b/packages/gatsby-plugin-offline/src/gatsby-node.js index c9000f45c9bae..70faced79c662 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-node.js +++ b/packages/gatsby-plugin-offline/src/gatsby-node.js @@ -79,15 +79,6 @@ exports.onPostBuild = (args, pluginOptions) => { // the default prefix with `pathPrefix`. "/": `${pathPrefix}/`, }, - navigateFallback: `${pathPrefix}/offline-plugin-app-shell-fallback/index.html`, - // Only match URLs without extensions. - // So example.com/about/ will pass but - // example.com/cheeseburger.jpg will not. - // We only want the service worker to handle our "clean" - // URLs and not any files hosted on the site. - // - // Regex based on http://stackoverflow.com/a/18017805 - navigateFallbackWhitelist: [/^([^.?]*|[^?]*\.([^.?]{5,}|html))(\?.*)?$/], cacheId: `gatsby-plugin-offline`, // Don't cache-bust JS or CSS files, and anything in the static directory dontCacheBustUrlsMatching: /(.*\.js$|.*\.css$|\/static\/)/, @@ -97,11 +88,6 @@ exports.onPostBuild = (args, pluginOptions) => { urlPattern: /\.(?:png|jpg|jpeg|webp|svg|gif|tiff|js|woff|woff2|json|css)$/, handler: `staleWhileRevalidate`, }, - { - // Use the Network First handler for external resources - urlPattern: /^https?:/, - handler: `networkFirst`, - }, ], skipWaiting: true, clientsClaim: true, @@ -119,9 +105,11 @@ exports.onPostBuild = (args, pluginOptions) => { .then(({ count, size, warnings }) => { if (warnings) warnings.forEach(warning => console.warn(warning)) - const swAppend = fs.readFileSync(`${__dirname}/sw-append.js`) - fs.appendFileSync(`public/sw.js`, swAppend) + const swAppend = fs + .readFileSync(`${__dirname}/sw-append.js`, `utf8`) + .replace(/%pathPrefix%/g, pathPrefix) + fs.appendFileSync(`public/sw.js`, swAppend) console.log( `Generated ${swDest}, which will precache ${count} files, totaling ${size} bytes.` ) diff --git a/packages/gatsby-plugin-offline/src/sw-append.js b/packages/gatsby-plugin-offline/src/sw-append.js index a578d3708a9e9..6793f95f9c175 100644 --- a/packages/gatsby-plugin-offline/src/sw-append.js +++ b/packages/gatsby-plugin-offline/src/sw-append.js @@ -1,8 +1,42 @@ -/* global workbox */ +/* global importScripts, workbox, idbKeyval */ -self.addEventListener(`message`, event => { - const { api } = event.data - if (api === `gatsby-runtime-cache`) { +importScripts( + `https://cdn.jsdelivr.net/npm/idb-keyval@3/dist/idb-keyval-iife.min.js` +) + +const WHITELIST_KEY = `custom-navigation-whitelist` + +const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => { + const url = new URL(event.request.url) + const pathname = url.pathname + url.search + console.log(`handling ${pathname}`) + + return idbKeyval.get(WHITELIST_KEY).then((customWhitelist = []) => { + // Respond with the offline shell if we match the custom whitelist + if (customWhitelist.includes(pathname)) { + const offlineShell = `%pathPrefix%/offline-plugin-app-shell-fallback/index.html` + const cacheName = workbox.core.cacheNames.precache + + console.log(`serving ${offlineShell} for ${pathname}`) + return caches.match(offlineShell, { cacheName }) + } + + console.log(`fetching ${pathname} from network`) + return fetch(event.request) + }) +}) + +workbox.routing.registerRoute(navigationRoute) + +// Handle any other requests with Network First, e.g. 3rd party resources +workbox.routing.registerRoute( + /^https?:/, + workbox.strategies.networkFirst(), + `GET` +) + +const messageApi = { + runtimeCache(event) { const { resources } = event.data const cacheName = workbox.core.cacheNames.runtime @@ -25,5 +59,28 @@ self.addEventListener(`message`, event => { ) ) ) - } + }, + + whitelistPathnames(event) { + const { pathnames } = event.data + + event.waitUntil( + idbKeyval.get(WHITELIST_KEY).then((customWhitelist = []) => { + pathnames.forEach(pathname => { + const prefixedPathname = `%pathPrefix%${pathname}` + if (!customWhitelist.includes(prefixedPathname)) { + console.log(`whitelisting ${prefixedPathname}`) + customWhitelist.push(prefixedPathname) + } + }) + + return idbKeyval.set(WHITELIST_KEY, customWhitelist) + }) + ) + }, +} + +self.addEventListener(`message`, event => { + const { gatsbyApi } = event.data + if (gatsbyApi) messageApi[gatsbyApi](event) }) From 1807752cf006fe3ae7dae97354e9fca98fe71db3 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 12 Nov 2018 17:48:11 +0000 Subject: [PATCH 04/21] Refactor whitelist code to allow it to support onPostPrefetchPathname --- .../gatsby-plugin-offline/src/gatsby-browser.js | 13 +++++++++---- packages/gatsby-plugin-offline/src/sw-append.js | 16 +++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/gatsby-plugin-offline/src/gatsby-browser.js b/packages/gatsby-plugin-offline/src/gatsby-browser.js index f8df48c8e7033..c41cc215a9736 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-browser.js +++ b/packages/gatsby-plugin-offline/src/gatsby-browser.js @@ -53,18 +53,23 @@ exports.onServiceWorkerActive = ({ }) } -exports.onRouteUpdate = ({ location }) => { +function whitelistPathname(pathname, includesPrefix) { if (`serviceWorker` in navigator) { const { serviceWorker } = navigator - const pathname = location.pathname + location.search if (serviceWorker.controller !== null) { serviceWorker.controller.postMessage({ gatsbyApi: `whitelistPathnames`, - pathnames: [pathname], + pathnames: [{ pathname, includesPrefix }], }) } else { - whitelistedPathnames.push(pathname) + whitelistedPathnames.push({ pathname, includesPrefix }) } } } + +exports.onRouteUpdate = ({ location }) => + whitelistPathname(location.pathname, true) + +exports.onPostPrefetchPathname = ({ pathname }) => + whitelistPathname(pathname, false) diff --git a/packages/gatsby-plugin-offline/src/sw-append.js b/packages/gatsby-plugin-offline/src/sw-append.js index 6793f95f9c175..af4ea90a9b550 100644 --- a/packages/gatsby-plugin-offline/src/sw-append.js +++ b/packages/gatsby-plugin-offline/src/sw-append.js @@ -7,8 +7,7 @@ importScripts( const WHITELIST_KEY = `custom-navigation-whitelist` const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => { - const url = new URL(event.request.url) - const pathname = url.pathname + url.search + const { pathname } = new URL(event.request.url) console.log(`handling ${pathname}`) return idbKeyval.get(WHITELIST_KEY).then((customWhitelist = []) => { @@ -66,11 +65,14 @@ const messageApi = { event.waitUntil( idbKeyval.get(WHITELIST_KEY).then((customWhitelist = []) => { - pathnames.forEach(pathname => { - const prefixedPathname = `%pathPrefix%${pathname}` - if (!customWhitelist.includes(prefixedPathname)) { - console.log(`whitelisting ${prefixedPathname}`) - customWhitelist.push(prefixedPathname) + pathnames.forEach(({ pathname, includesPrefix }) => { + if (!includesPrefix) { + pathname = `%pathPrefix%${pathname}` + } + + if (!customWhitelist.includes(pathname)) { + console.log(`whitelisting ${pathname}`) + customWhitelist.push(pathname) } }) From 8f3cd4bdc3df683315035cb39b4e7dc0991470bb Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 12 Nov 2018 18:02:39 +0000 Subject: [PATCH 05/21] Fix service worker detection --- .../src/gatsby-browser.js | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/gatsby-plugin-offline/src/gatsby-browser.js b/packages/gatsby-plugin-offline/src/gatsby-browser.js index c41cc215a9736..6ce383631e9d4 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-browser.js +++ b/packages/gatsby-plugin-offline/src/gatsby-browser.js @@ -1,26 +1,12 @@ exports.registerServiceWorker = () => true -let swNotInstalled = true const prefetchedPathnames = [] const whitelistedPathnames = [] -// TODO - check if swNotInstalled is true when the SW is actually installed -// (causing duplicate cache storage) -exports.onPostPrefetchPathname = ({ pathname }) => { - // if SW is not installed, we need to record any prefetches - // that happen so we can then add them to SW cache once installed - if (swNotInstalled && `serviceWorker` in navigator) { - prefetchedPathnames.push(pathname) - } -} - exports.onServiceWorkerActive = ({ getResourceURLsForPathname, serviceWorker, }) => { - // stop recording prefetch events - swNotInstalled = false - // grab nodes from head of document const nodes = document.querySelectorAll(` head > script[src], @@ -71,5 +57,19 @@ function whitelistPathname(pathname, includesPrefix) { exports.onRouteUpdate = ({ location }) => whitelistPathname(location.pathname, true) -exports.onPostPrefetchPathname = ({ pathname }) => +exports.onPostPrefetchPathname = ({ pathname }) => { whitelistPathname(pathname, false) + + // if SW is not installed, we need to record any prefetches + // that happen so we can then add them to SW cache once installed + if ( + `serviceWorker` in navigator && + !( + navigator.serviceWorker.controller !== null && + navigator.serviceWorker.controller.state === `activated` + ) + ) { + console.log(`SERVICE WORKER NOT INSTALLED`) + prefetchedPathnames.push(pathname) + } +} From 8d826c6b7ca9f63c33e97ec1072724a54f0c1dae Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 12 Nov 2018 18:25:17 +0000 Subject: [PATCH 06/21] Fix IndexedDB race condition --- packages/gatsby-plugin-offline/src/sw-append.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/gatsby-plugin-offline/src/sw-append.js b/packages/gatsby-plugin-offline/src/sw-append.js index af4ea90a9b550..0e6defb27b9c9 100644 --- a/packages/gatsby-plugin-offline/src/sw-append.js +++ b/packages/gatsby-plugin-offline/src/sw-append.js @@ -5,12 +5,24 @@ importScripts( ) const WHITELIST_KEY = `custom-navigation-whitelist` +let customWhitelist = null + +function initWhitelist() { + return new Promise(resolve => { + if (customWhitelist !== null) resolve() + + idbKeyval.get(WHITELIST_KEY).then(initialData => { + customWhitelist = initialData || [] + resolve() + }) + }) +} const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => { const { pathname } = new URL(event.request.url) console.log(`handling ${pathname}`) - return idbKeyval.get(WHITELIST_KEY).then((customWhitelist = []) => { + return initWhitelist.then(() => { // Respond with the offline shell if we match the custom whitelist if (customWhitelist.includes(pathname)) { const offlineShell = `%pathPrefix%/offline-plugin-app-shell-fallback/index.html` @@ -64,7 +76,7 @@ const messageApi = { const { pathnames } = event.data event.waitUntil( - idbKeyval.get(WHITELIST_KEY).then((customWhitelist = []) => { + initWhitelist().then(() => { pathnames.forEach(({ pathname, includesPrefix }) => { if (!includesPrefix) { pathname = `%pathPrefix%${pathname}` From e8224ea623f658da6afb350a51256f1a0b20ad34 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 12 Nov 2018 20:23:20 +0000 Subject: [PATCH 07/21] Prevent race conditions + reset whitelist on SW update --- .../gatsby-plugin-offline/src/sw-append.js | 86 ++++++++++++------- packages/gatsby/cache-dir/navigation.js | 6 +- 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/packages/gatsby-plugin-offline/src/sw-append.js b/packages/gatsby-plugin-offline/src/sw-append.js index 0e6defb27b9c9..68ba5a4b404b7 100644 --- a/packages/gatsby-plugin-offline/src/sw-append.js +++ b/packages/gatsby-plugin-offline/src/sw-append.js @@ -5,24 +5,12 @@ importScripts( ) const WHITELIST_KEY = `custom-navigation-whitelist` -let customWhitelist = null - -function initWhitelist() { - return new Promise(resolve => { - if (customWhitelist !== null) resolve() - - idbKeyval.get(WHITELIST_KEY).then(initialData => { - customWhitelist = initialData || [] - resolve() - }) - }) -} const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => { const { pathname } = new URL(event.request.url) console.log(`handling ${pathname}`) - return initWhitelist.then(() => { + return idbKeyval.get(WHITELIST_KEY).then((customWhitelist = []) => { // Respond with the offline shell if we match the custom whitelist if (customWhitelist.includes(pathname)) { const offlineShell = `%pathPrefix%/offline-plugin-app-shell-fallback/index.html` @@ -39,13 +27,51 @@ const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => { workbox.routing.registerRoute(navigationRoute) -// Handle any other requests with Network First, e.g. 3rd party resources +// Handle any other requests with Network First, e.g. 3rd party resources. +// This needs to be done last, otherwise it will prevent the custom navigation +// route from working (and any other rules). workbox.routing.registerRoute( /^https?:/, workbox.strategies.networkFirst(), `GET` ) +let updatingWhitelist = null + +function rawWhitelistPathnames(pathnames) { + if (updatingWhitelist !== null) { + // Prevent the whitelist from being updated twice at the same time + return updatingWhitelist.then(() => rawWhitelistPathnames(pathnames)) + } + + updatingWhitelist = idbKeyval + .get(WHITELIST_KEY) + .then((customWhitelist = []) => { + pathnames.forEach(pathname => { + if (!customWhitelist.includes(pathname)) customWhitelist.push(pathname) + }) + + return idbKeyval.set(WHITELIST_KEY, customWhitelist) + }) + .then(() => { + updatingWhitelist = null + }) + + return updatingWhitelist +} + +function rawResetWhitelist() { + if (updatingWhitelist !== null) { + return updatingWhitelist.then(() => rawResetWhitelist()) + } + + updatingWhitelist = idbKeyval.set(WHITELIST_KEY, []).then(() => { + updatingWhitelist = null + }) + + return updatingWhitelist +} + const messageApi = { runtimeCache(event) { const { resources } = event.data @@ -73,24 +99,22 @@ const messageApi = { }, whitelistPathnames(event) { - const { pathnames } = event.data + let { pathnames } = event.data + + pathnames = pathnames.map(({ pathname, includesPrefix }) => { + if (!includesPrefix) { + return `%pathPrefix%${pathname}` + } else { + return pathname + } + }) - event.waitUntil( - initWhitelist().then(() => { - pathnames.forEach(({ pathname, includesPrefix }) => { - if (!includesPrefix) { - pathname = `%pathPrefix%${pathname}` - } - - if (!customWhitelist.includes(pathname)) { - console.log(`whitelisting ${pathname}`) - customWhitelist.push(pathname) - } - }) - - return idbKeyval.set(WHITELIST_KEY, customWhitelist) - }) - ) + console.log(`setting whitelist`) + event.waitUntil(rawWhitelistPathnames(pathnames)) + }, + + resetWhitelist(event) { + event.waitUntil(rawResetWhitelist()) }, } diff --git a/packages/gatsby/cache-dir/navigation.js b/packages/gatsby/cache-dir/navigation.js index ad4fecb1898e1..2eac830df82d2 100644 --- a/packages/gatsby/cache-dir/navigation.js +++ b/packages/gatsby/cache-dir/navigation.js @@ -65,8 +65,12 @@ const navigate = (to, options = {}) => { pathname = parsePath(to).pathname } - // If we had a service worker update, no matter the path, reload window + // 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` }) + window.location = pathname return } From c60bb5ca0da56aebb6265487cdc756fc37adeb52 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 12 Nov 2018 20:29:10 +0000 Subject: [PATCH 08/21] Remove unnecessary API handler (onPostPrefetchPathname is called anyway) --- packages/gatsby-plugin-offline/src/gatsby-browser.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/gatsby-plugin-offline/src/gatsby-browser.js b/packages/gatsby-plugin-offline/src/gatsby-browser.js index 6ce383631e9d4..f779395806d42 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-browser.js +++ b/packages/gatsby-plugin-offline/src/gatsby-browser.js @@ -54,10 +54,8 @@ function whitelistPathname(pathname, includesPrefix) { } } -exports.onRouteUpdate = ({ location }) => - whitelistPathname(location.pathname, true) - exports.onPostPrefetchPathname = ({ pathname }) => { + console.log(`onPostPrefetchPathname ${pathname}`) whitelistPathname(pathname, false) // if SW is not installed, we need to record any prefetches From 465a4d294cb37e43284a7f8af22e162a174113f4 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Tue, 13 Nov 2018 19:29:08 +0000 Subject: [PATCH 09/21] Add debugging statements + fix some minor problems --- packages/gatsby/cache-dir/ensure-resources.js | 5 +- packages/gatsby/cache-dir/loader.js | 52 ++++++++++++------- packages/gatsby/cache-dir/navigation.js | 11 +--- packages/gatsby/cache-dir/prefetch.js | 2 + 4 files changed, 40 insertions(+), 30 deletions(-) diff --git a/packages/gatsby/cache-dir/ensure-resources.js b/packages/gatsby/cache-dir/ensure-resources.js index 95cc5620110af..a64d82c3ef477 100644 --- a/packages/gatsby/cache-dir/ensure-resources.js +++ b/packages/gatsby/cache-dir/ensure-resources.js @@ -93,11 +93,14 @@ class EnsureResources extends React.Component { } render() { - // This should only occur if there's no custom 404 page + // This should only occur if the network is offline, or if the + // path is nonexistent and there's no custom 404 page. if ( process.env.NODE_ENV === `production` && !(this.state.pageResources && this.state.pageResources.json) ) { + console.error(`Failed to get resources for ${location.pathname}`) + window.location.reload() return null } diff --git a/packages/gatsby/cache-dir/loader.js b/packages/gatsby/cache-dir/loader.js index 392d12e285477..a312d5339839f 100644 --- a/packages/gatsby/cache-dir/loader.js +++ b/packages/gatsby/cache-dir/loader.js @@ -1,6 +1,5 @@ import pageFinderFactory from "./find-page" import emitter from "./emitter" -import stripPrefix from "./strip-prefix" import prefetchHelper from "./prefetch" const preferDefault = m => (m && m.default) || m @@ -16,7 +15,6 @@ let fetchingPageResourceMapPromise = null let fetchedPageResourceMap = false let apiRunner const failedPaths = {} -const failedResources = {} const MAX_HISTORY = 5 const jsonPromiseStore = {} @@ -53,25 +51,38 @@ const createComponentUrls = componentChunkName => ) const fetchResource = resourceName => { + console.log(`fetchResource ${resourceName}`) // Find resource let resourceFunction if (resourceName.slice(0, 12) === `component---`) { + console.log( + `resourceFunction: resolving ${resourceName} with asyncRequires.components:` + ) + console.log(asyncRequires.components) resourceFunction = asyncRequires.components[resourceName] } else { if (resourceName in jsonPromiseStore) { + console.log( + `resourceFunction: found ${resourceName} in jsonPromiseStore:` + ) + console.log(jsonPromiseStore) resourceFunction = () => jsonPromiseStore[resourceName] } else { resourceFunction = () => { const fetchPromise = new Promise((resolve, reject) => { const url = createJsonURL(jsonDataPaths[resourceName]) + console.log(`resourceFunction: fetching ${url} from network`) const req = new XMLHttpRequest() req.open(`GET`, url, true) req.withCredentials = true req.onreadystatechange = () => { if (req.readyState == 4) { if (req.status === 200) { + console.log(`resolving ${url}`) resolve(JSON.parse(req.responseText)) } else { + console.log(`rejecting ${url} - didn't return 200`) + delete jsonPromiseStore[resourceName] reject() } } @@ -90,7 +101,9 @@ const fetchResource = resourceName => { const fetchPromise = resourceFunction() let failed = false return fetchPromise - .catch(() => { + .catch(e => { + console.log(`fetchPromise for ${resourceName} failed:`) + console.error(e) failed = true }) .then(component => { @@ -99,18 +112,17 @@ const fetchResource = resourceName => { succeeded: !failed, }) - if (!failedResources[resourceName]) { - failedResources[resourceName] = failed - } - fetchHistory = fetchHistory.slice(-MAX_HISTORY) + console.log(`finally resolving fetchResource for ${resourceName} with:`) + console.log(component) resolve(component) }) }) } const prefetchResource = resourceName => { + console.log(`prefetchResource ${resourceName}`) if (resourceName.slice(0, 12) === `component---`) { createComponentUrls(resourceName).forEach(url => prefetchHelper(url)) } else { @@ -134,6 +146,7 @@ const appearsOnLine = () => { } const handleResourceLoadError = (path, message) => { + console.log(`handleResourceLoadError for path ${path}`) if (!failedPaths[path]) { failedPaths[path] = message } @@ -148,14 +161,14 @@ const handleResourceLoadError = (path, message) => { const onPrefetchPathname = pathname => { if (!prefetchTriggered[pathname]) { - apiRunner(`onPrefetchPathname`, { pathname: pathname }) + apiRunner(`onPrefetchPathname`, { pathname }) prefetchTriggered[pathname] = true } } const onPostPrefetchPathname = pathname => { if (!prefetchCompleted[pathname]) { - apiRunner(`onPostPrefetchPathname`, { pathname: pathname }) + apiRunner(`onPostPrefetchPathname`, { pathname }) prefetchCompleted[pathname] = true } } @@ -188,12 +201,10 @@ const queue = { // Hovering on a link is a very strong indication the user is going to // click on it soon so let's start prefetching resources for this // pathname. - hovering: rawPath => { - const path = stripPrefix(rawPath, __PATH_PREFIX__) + hovering: path => { queue.getResourcesForPathname(path) }, - enqueue: rawPath => { - const path = stripPrefix(rawPath, __PATH_PREFIX__) + enqueue: path => { if (!apiRunner) console.error(`Run setApiRunnerForLoader() before enqueing paths`) @@ -218,7 +229,7 @@ const queue = { ) { // If page wasn't found check and we didn't fetch resources map for // all pages, wait for fetch to complete and try find page again - return fetchPageResourceMap().then(() => queue.enqueue(rawPath)) + return fetchPageResourceMap().then(() => queue.enqueue(path)) } if (!page) { @@ -238,9 +249,6 @@ const queue = { prefetchResource(page.componentChunkName) } - // Tell plugins the path has been successfully prefetched - onPostPrefetchPathname(path) - return true }, @@ -274,6 +282,7 @@ const queue = { // and getting resources for page changes. getResourcesForPathname: path => new Promise((resolve, reject) => { + console.log(`getResourcesForPathname ${path}`) const doingInitialRender = inInitialRender inInitialRender = false @@ -350,6 +359,9 @@ const queue = { page, pageResources, }) + // Tell plugins the path has been successfully prefetched + onPostPrefetchPathname(path) + resolve(pageResources) }) } else { @@ -378,6 +390,9 @@ const queue = { pageResources, }) + // Tell plugins the path has been successfully prefetched + onPostPrefetchPathname(path) + if (doingInitialRender) { // We got all resources needed for first mount, // we can fetch resoures for all pages. @@ -385,9 +400,6 @@ const queue = { } }) } - - // Tell plugins the path has been successfully prefetched - onPostPrefetchPathname(path) }), } diff --git a/packages/gatsby/cache-dir/navigation.js b/packages/gatsby/cache-dir/navigation.js index 2eac830df82d2..1932dfc64d491 100644 --- a/packages/gatsby/cache-dir/navigation.js +++ b/packages/gatsby/cache-dir/navigation.js @@ -85,15 +85,8 @@ const navigate = (to, options = {}) => { }, 1000) loader.getResourcesForPathname(pathname).then(pageResources => { - if (!pageResources && process.env.NODE_ENV === `production`) { - loader.getResourcesForPathname(`/404.html`).then(() => { - clearTimeout(timeoutId) - reachNavigate(to, options) - }) - } else { - reachNavigate(to, options) - clearTimeout(timeoutId) - } + reachNavigate(to, options) + clearTimeout(timeoutId) }) } diff --git a/packages/gatsby/cache-dir/prefetch.js b/packages/gatsby/cache-dir/prefetch.js index 82c119ccb5a43..a07b5d70d8a11 100644 --- a/packages/gatsby/cache-dir/prefetch.js +++ b/packages/gatsby/cache-dir/prefetch.js @@ -39,9 +39,11 @@ const preFetched = {} const prefetch = function(url) { if (preFetched[url]) { + console.log(`prefetch ${url}: already prefetched`) return } preFetched[url] = true + console.log(`prefetch ${url}: actually doing it now`) supportedPrefetchStrategy(url) } From c62c378e7d50ffa83792b43b69c05111d6be8a6c Mon Sep 17 00:00:00 2001 From: David Bailey Date: Tue, 13 Nov 2018 20:11:00 +0000 Subject: [PATCH 10/21] Fix back/forward not working after 404 --- packages/gatsby/cache-dir/ensure-resources.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/gatsby/cache-dir/ensure-resources.js b/packages/gatsby/cache-dir/ensure-resources.js index a64d82c3ef477..b623104257559 100644 --- a/packages/gatsby/cache-dir/ensure-resources.js +++ b/packages/gatsby/cache-dir/ensure-resources.js @@ -100,7 +100,15 @@ class EnsureResources extends React.Component { !(this.state.pageResources && this.state.pageResources.json) ) { console.error(`Failed to get resources for ${location.pathname}`) - window.location.reload() + + // Do this, rather than simply `window.location.reload()`, so that + // pressing the back/forward buttons work - otherwise Reach Router will + // try to handle back/forward navigation, causing the URL to change but + // the page displayed to stay the same. + const originalUrl = new URL(location.href) + window.history.replaceState({}, `404`, `${location.pathname}?gatsby-404`) + window.location.replace(originalUrl) + return null } From 4d47124f3a554aacf81054b3be3836cd0bea837e Mon Sep 17 00:00:00 2001 From: David Bailey Date: Tue, 13 Nov 2018 20:47:39 +0000 Subject: [PATCH 11/21] Remove unneeded debugging statements --- .../src/gatsby-browser.js | 2 -- .../gatsby-plugin-offline/src/sw-append.js | 4 ---- packages/gatsby/cache-dir/ensure-resources.js | 2 -- packages/gatsby/cache-dir/loader.js | 18 ------------------ packages/gatsby/cache-dir/prefetch.js | 2 -- 5 files changed, 28 deletions(-) diff --git a/packages/gatsby-plugin-offline/src/gatsby-browser.js b/packages/gatsby-plugin-offline/src/gatsby-browser.js index f779395806d42..91efe47d311c7 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-browser.js +++ b/packages/gatsby-plugin-offline/src/gatsby-browser.js @@ -55,7 +55,6 @@ function whitelistPathname(pathname, includesPrefix) { } exports.onPostPrefetchPathname = ({ pathname }) => { - console.log(`onPostPrefetchPathname ${pathname}`) whitelistPathname(pathname, false) // if SW is not installed, we need to record any prefetches @@ -67,7 +66,6 @@ exports.onPostPrefetchPathname = ({ pathname }) => { navigator.serviceWorker.controller.state === `activated` ) ) { - console.log(`SERVICE WORKER NOT INSTALLED`) prefetchedPathnames.push(pathname) } } diff --git a/packages/gatsby-plugin-offline/src/sw-append.js b/packages/gatsby-plugin-offline/src/sw-append.js index 68ba5a4b404b7..fa36ff91776b4 100644 --- a/packages/gatsby-plugin-offline/src/sw-append.js +++ b/packages/gatsby-plugin-offline/src/sw-append.js @@ -8,7 +8,6 @@ const WHITELIST_KEY = `custom-navigation-whitelist` const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => { const { pathname } = new URL(event.request.url) - console.log(`handling ${pathname}`) return idbKeyval.get(WHITELIST_KEY).then((customWhitelist = []) => { // Respond with the offline shell if we match the custom whitelist @@ -16,11 +15,9 @@ const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => { const offlineShell = `%pathPrefix%/offline-plugin-app-shell-fallback/index.html` const cacheName = workbox.core.cacheNames.precache - console.log(`serving ${offlineShell} for ${pathname}`) return caches.match(offlineShell, { cacheName }) } - console.log(`fetching ${pathname} from network`) return fetch(event.request) }) }) @@ -109,7 +106,6 @@ const messageApi = { } }) - console.log(`setting whitelist`) event.waitUntil(rawWhitelistPathnames(pathnames)) }, diff --git a/packages/gatsby/cache-dir/ensure-resources.js b/packages/gatsby/cache-dir/ensure-resources.js index b623104257559..c05a82673ae29 100644 --- a/packages/gatsby/cache-dir/ensure-resources.js +++ b/packages/gatsby/cache-dir/ensure-resources.js @@ -99,8 +99,6 @@ class EnsureResources extends React.Component { process.env.NODE_ENV === `production` && !(this.state.pageResources && this.state.pageResources.json) ) { - console.error(`Failed to get resources for ${location.pathname}`) - // Do this, rather than simply `window.location.reload()`, so that // pressing the back/forward buttons work - otherwise Reach Router will // try to handle back/forward navigation, causing the URL to change but diff --git a/packages/gatsby/cache-dir/loader.js b/packages/gatsby/cache-dir/loader.js index a312d5339839f..67293bf8660e9 100644 --- a/packages/gatsby/cache-dir/loader.js +++ b/packages/gatsby/cache-dir/loader.js @@ -51,37 +51,25 @@ const createComponentUrls = componentChunkName => ) const fetchResource = resourceName => { - console.log(`fetchResource ${resourceName}`) // Find resource let resourceFunction if (resourceName.slice(0, 12) === `component---`) { - console.log( - `resourceFunction: resolving ${resourceName} with asyncRequires.components:` - ) - console.log(asyncRequires.components) resourceFunction = asyncRequires.components[resourceName] } else { if (resourceName in jsonPromiseStore) { - console.log( - `resourceFunction: found ${resourceName} in jsonPromiseStore:` - ) - console.log(jsonPromiseStore) resourceFunction = () => jsonPromiseStore[resourceName] } else { resourceFunction = () => { const fetchPromise = new Promise((resolve, reject) => { const url = createJsonURL(jsonDataPaths[resourceName]) - console.log(`resourceFunction: fetching ${url} from network`) const req = new XMLHttpRequest() req.open(`GET`, url, true) req.withCredentials = true req.onreadystatechange = () => { if (req.readyState == 4) { if (req.status === 200) { - console.log(`resolving ${url}`) resolve(JSON.parse(req.responseText)) } else { - console.log(`rejecting ${url} - didn't return 200`) delete jsonPromiseStore[resourceName] reject() } @@ -102,7 +90,6 @@ const fetchResource = resourceName => { let failed = false return fetchPromise .catch(e => { - console.log(`fetchPromise for ${resourceName} failed:`) console.error(e) failed = true }) @@ -114,15 +101,12 @@ const fetchResource = resourceName => { fetchHistory = fetchHistory.slice(-MAX_HISTORY) - console.log(`finally resolving fetchResource for ${resourceName} with:`) - console.log(component) resolve(component) }) }) } const prefetchResource = resourceName => { - console.log(`prefetchResource ${resourceName}`) if (resourceName.slice(0, 12) === `component---`) { createComponentUrls(resourceName).forEach(url => prefetchHelper(url)) } else { @@ -146,7 +130,6 @@ const appearsOnLine = () => { } const handleResourceLoadError = (path, message) => { - console.log(`handleResourceLoadError for path ${path}`) if (!failedPaths[path]) { failedPaths[path] = message } @@ -282,7 +265,6 @@ const queue = { // and getting resources for page changes. getResourcesForPathname: path => new Promise((resolve, reject) => { - console.log(`getResourcesForPathname ${path}`) const doingInitialRender = inInitialRender inInitialRender = false diff --git a/packages/gatsby/cache-dir/prefetch.js b/packages/gatsby/cache-dir/prefetch.js index a07b5d70d8a11..82c119ccb5a43 100644 --- a/packages/gatsby/cache-dir/prefetch.js +++ b/packages/gatsby/cache-dir/prefetch.js @@ -39,11 +39,9 @@ const preFetched = {} const prefetch = function(url) { if (preFetched[url]) { - console.log(`prefetch ${url}: already prefetched`) return } preFetched[url] = true - console.log(`prefetch ${url}: actually doing it now`) supportedPrefetchStrategy(url) } From b233cf6d868e0d7caeeb8530cf6f3ad5b359d679 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Tue, 13 Nov 2018 21:21:57 +0000 Subject: [PATCH 12/21] Bundle idb-keyval instead of using an external CDN --- packages/gatsby-plugin-offline/package.json | 1 + packages/gatsby-plugin-offline/src/gatsby-node.js | 5 +++++ packages/gatsby-plugin-offline/src/sw-append.js | 5 +---- yarn.lock | 5 +++++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/gatsby-plugin-offline/package.json b/packages/gatsby-plugin-offline/package.json index 3a51bd18b2e96..e6150ee8ca38f 100644 --- a/packages/gatsby-plugin-offline/package.json +++ b/packages/gatsby-plugin-offline/package.json @@ -9,6 +9,7 @@ "dependencies": { "@babel/runtime": "^7.0.0", "cheerio": "^1.0.0-rc.2", + "idb-keyval": "^3.1.0", "lodash": "^4.17.10", "workbox-build": "^3.6.3" }, diff --git a/packages/gatsby-plugin-offline/src/gatsby-node.js b/packages/gatsby-plugin-offline/src/gatsby-node.js index 70faced79c662..6433cec50957c 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-node.js +++ b/packages/gatsby-plugin-offline/src/gatsby-node.js @@ -99,6 +99,11 @@ exports.onPostBuild = (args, pluginOptions) => { delete pluginOptions.plugins const combinedOptions = _.defaults(pluginOptions, options) + const idbKeyvalFile = `idb-keyval-iife.min.js` + const idbKeyvalSource = require.resolve(`idb-keyval/dist/${idbKeyvalFile}`) + const idbKeyvalDest = `public/${idbKeyvalFile}` + fs.createReadStream(idbKeyvalSource).pipe(fs.createWriteStream(idbKeyvalDest)) + const swDest = `public/sw.js` return workboxBuild .generateSW({ swDest, ...combinedOptions }) diff --git a/packages/gatsby-plugin-offline/src/sw-append.js b/packages/gatsby-plugin-offline/src/sw-append.js index fa36ff91776b4..79f64ccf75a1c 100644 --- a/packages/gatsby-plugin-offline/src/sw-append.js +++ b/packages/gatsby-plugin-offline/src/sw-append.js @@ -1,9 +1,6 @@ /* global importScripts, workbox, idbKeyval */ -importScripts( - `https://cdn.jsdelivr.net/npm/idb-keyval@3/dist/idb-keyval-iife.min.js` -) - +importScripts(`idb-keyval-iife.min.js`) const WHITELIST_KEY = `custom-navigation-whitelist` const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => { diff --git a/yarn.lock b/yarn.lock index 8a0b3ae8e7707..872775a9ace38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9862,6 +9862,11 @@ icss-utils@^2.1.0: dependencies: postcss "^6.0.1" +idb-keyval@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-3.1.0.tgz#cce9ed320734446784d52ed398c4b075a4273f51" + integrity sha512-iFwFN5n00KNNnVxlOOK280SJJfXWY7pbMUOQXdIXehvvc/mGCV/6T2Ae+Pk2KwAkkATDTwfMavOiDH5lrJKWXQ== + ieee754@^1.1.4: version "1.1.12" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" From 7c4a2b606c28ce6d48971479da907f4514ae8ca8 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Tue, 13 Nov 2018 21:45:55 +0000 Subject: [PATCH 13/21] Update README --- packages/gatsby-plugin-offline/README.md | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/packages/gatsby-plugin-offline/README.md b/packages/gatsby-plugin-offline/README.md index 0ba71cf91163e..37b9faf3b5477 100644 --- a/packages/gatsby-plugin-offline/README.md +++ b/packages/gatsby-plugin-offline/README.md @@ -24,8 +24,8 @@ plugins: [`gatsby-plugin-offline`] When adding this plugin to your `gatsby-config.js`, you can pass in options to override the default [Workbox](https://developers.google.com/web/tools/workbox/modules/workbox-build) config. -The default config is as follows. Warning, you can break the offline support -and AppCache setup by changing these options so tread carefully. +The default config is as follows. Warning: you can break the offline support by +changing these options, so tread carefully. ```javascript const options = { @@ -33,25 +33,13 @@ const options = { globDirectory: rootDir, globPatterns, modifyUrlPrefix: { - rootDir: ``, // If `pathPrefix` is configured by user, we should replace // the default prefix with `pathPrefix`. - "": args.pathPrefix || ``, + "/": `${pathPrefix}/`, }, - navigateFallback: `/offline-plugin-app-shell-fallback/index.html`, - // Only match URLs without extensions or the query `no-cache=1`. - // So example.com/about/ will pass but - // example.com/about/?no-cache=1 and - // example.com/cheeseburger.jpg will not. - // We only want the service worker to handle our "clean" - // URLs and not any files hosted on the site. - // - // Regex based on http://stackoverflow.com/a/18017805 - navigateFallbackWhitelist: [/^[^?]*([^.?]{5}|\.html)(\?.*)?$/], - navigateFallbackBlacklist: [/\?(.+&)?no-cache=1$/], cacheId: `gatsby-plugin-offline`, - // Don't cache-bust JS files and anything in the static directory - dontCacheBustUrlsMatching: /(.*js$|\/static\/)/, + // Don't cache-bust JS or CSS files, and anything in the static directory + dontCacheBustUrlsMatching: /(.*\.js$|.*\.css$|\/static\/)/, runtimeCaching: [ { // Add runtime caching of various page resources. From 25e4ecf0fe0d09ee59babb91ac410048caf9e4a2 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Wed, 14 Nov 2018 14:02:19 +0000 Subject: [PATCH 14/21] Fix excessive file caching (e.g. GA tracking gif) --- .../src/gatsby-browser.js | 18 ++++++---- .../gatsby-plugin-offline/src/gatsby-node.js | 7 +++- .../gatsby-plugin-offline/src/sw-append.js | 34 ------------------- 3 files changed, 18 insertions(+), 41 deletions(-) diff --git a/packages/gatsby-plugin-offline/src/gatsby-browser.js b/packages/gatsby-plugin-offline/src/gatsby-browser.js index 91efe47d311c7..2cab97b51b77f 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-browser.js +++ b/packages/gatsby-plugin-offline/src/gatsby-browser.js @@ -10,13 +10,12 @@ exports.onServiceWorkerActive = ({ // grab nodes from head of document const nodes = document.querySelectorAll(` head > script[src], - head > link[as=script], - head > link[rel=stylesheet], + head > link[href], head > style[data-href] `) // get all resource URLs - const resources = [].slice + const headerResources = [].slice .call(nodes) .map(node => node.src || node.href || node.getAttribute(`data-href`)) @@ -29,10 +28,17 @@ exports.onServiceWorkerActive = ({ ) ) - serviceWorker.active.postMessage({ - gatsbyApi: `runtimeCache`, - resources: [...resources, ...prefetchedResources], + const resources = [...headerResources, ...prefetchedResources] + resources.forEach(resource => { + // Create a prefetch link for each resource, so Workbox runtime-caches them + const link = document.createElement(`link`) + link.rel = `prefetch` + link.href = resource + + document.head.appendChild(link) + link.onload = link.remove }) + serviceWorker.active.postMessage({ gatsbyApi: `whitelistPathnames`, pathnames: whitelistedPathnames, diff --git a/packages/gatsby-plugin-offline/src/gatsby-node.js b/packages/gatsby-plugin-offline/src/gatsby-node.js index 6433cec50957c..40902426ff6bd 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-node.js +++ b/packages/gatsby-plugin-offline/src/gatsby-node.js @@ -85,7 +85,12 @@ exports.onPostBuild = (args, pluginOptions) => { runtimeCaching: [ { // Add runtime caching of various page resources. - urlPattern: /\.(?:png|jpg|jpeg|webp|svg|gif|tiff|js|woff|woff2|json|css)$/, + urlPattern: /^https?:.*\.(?:png|jpg|jpeg|webp|svg|gif|tiff|js|woff|woff2|json|css)$/, + handler: `staleWhileRevalidate`, + }, + { + // Google Fonts CSS (doesn't end in .css so we need to specify it) + urlPattern: /^https?:\/\/fonts\.googleapis\.com\/css/, handler: `staleWhileRevalidate`, }, ], diff --git a/packages/gatsby-plugin-offline/src/sw-append.js b/packages/gatsby-plugin-offline/src/sw-append.js index 79f64ccf75a1c..0d6c4a191d467 100644 --- a/packages/gatsby-plugin-offline/src/sw-append.js +++ b/packages/gatsby-plugin-offline/src/sw-append.js @@ -21,15 +21,6 @@ const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => { workbox.routing.registerRoute(navigationRoute) -// Handle any other requests with Network First, e.g. 3rd party resources. -// This needs to be done last, otherwise it will prevent the custom navigation -// route from working (and any other rules). -workbox.routing.registerRoute( - /^https?:/, - workbox.strategies.networkFirst(), - `GET` -) - let updatingWhitelist = null function rawWhitelistPathnames(pathnames) { @@ -67,31 +58,6 @@ function rawResetWhitelist() { } const messageApi = { - runtimeCache(event) { - const { resources } = event.data - const cacheName = workbox.core.cacheNames.runtime - - event.waitUntil( - caches.open(cacheName).then(cache => - Promise.all( - resources.map(resource => { - let request - - // Some external resources don't allow - // CORS so get an opaque response - if (resource.match(/^https?:/)) { - request = fetch(resource, { mode: `no-cors` }) - } else { - request = fetch(resource) - } - - return request.then(response => cache.put(resource, response)) - }) - ) - ) - ) - }, - whitelistPathnames(event) { let { pathnames } = event.data From 23599eb9cc22330cb71ef9536540fb8162b4d2bd Mon Sep 17 00:00:00 2001 From: David Bailey Date: Wed, 14 Nov 2018 14:12:20 +0000 Subject: [PATCH 15/21] Backport fixes from #9907 --- .../src/gatsby-browser.js | 16 ++++++---- .../gatsby-plugin-offline/src/gatsby-node.js | 7 ++--- .../gatsby-plugin-offline/src/sw-append.js | 30 +------------------ 3 files changed, 14 insertions(+), 39 deletions(-) diff --git a/packages/gatsby-plugin-offline/src/gatsby-browser.js b/packages/gatsby-plugin-offline/src/gatsby-browser.js index 318efddceac57..4f7beac2f9809 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-browser.js +++ b/packages/gatsby-plugin-offline/src/gatsby-browser.js @@ -21,13 +21,12 @@ exports.onServiceWorkerActive = ({ // grab nodes from head of document const nodes = document.querySelectorAll(` head > script[src], - head > link[as=script], - head > link[rel=stylesheet], + head > link[href], head > style[data-href] `) // get all resource URLs - const resources = [].slice + const headerResources = [].slice .call(nodes) .map(node => node.src || node.href || node.getAttribute(`data-href`)) @@ -40,8 +39,13 @@ exports.onServiceWorkerActive = ({ ) ) - serviceWorker.active.postMessage({ - api: `gatsby-runtime-cache`, - resources: [...resources, ...prefetchedResources], + const resources = [...headerResources, ...prefetchedResources] + resources.forEach(resource => { + // Create a prefetch link for each resource, so Workbox runtime-caches them + const link = document.createElement(`link`) + link.rel = `prefetch` + link.href = resource + document.head.appendChild(link) + link.onload = link.remove }) } diff --git a/packages/gatsby-plugin-offline/src/gatsby-node.js b/packages/gatsby-plugin-offline/src/gatsby-node.js index a9f4419e93d21..c8b3520ebe254 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-node.js +++ b/packages/gatsby-plugin-offline/src/gatsby-node.js @@ -96,13 +96,12 @@ exports.onPostBuild = (args, pluginOptions) => { runtimeCaching: [ { // Add runtime caching of various page resources. - urlPattern: /\.(?:png|jpg|jpeg|webp|svg|gif|tiff|js|woff|woff2|json|css)$/, + urlPattern: /^https?:.*\.(?:png|jpg|jpeg|webp|svg|gif|tiff|js|woff|woff2|json|css)$/, handler: `staleWhileRevalidate`, }, { - // Use the Network First handler for external resources - urlPattern: /^https?:/, - handler: `networkFirst`, + // Google Fonts CSS (doesn't end in .css so we need to specify it) + urlPattern: /^https?:\/\/fonts\.googleapis\.com\/css/, }, ], skipWaiting: true, diff --git a/packages/gatsby-plugin-offline/src/sw-append.js b/packages/gatsby-plugin-offline/src/sw-append.js index a578d3708a9e9..172f1ae6a468c 100644 --- a/packages/gatsby-plugin-offline/src/sw-append.js +++ b/packages/gatsby-plugin-offline/src/sw-append.js @@ -1,29 +1 @@ -/* global workbox */ - -self.addEventListener(`message`, event => { - const { api } = event.data - if (api === `gatsby-runtime-cache`) { - const { resources } = event.data - const cacheName = workbox.core.cacheNames.runtime - - event.waitUntil( - caches.open(cacheName).then(cache => - Promise.all( - resources.map(resource => { - let request - - // Some external resources don't allow - // CORS so get an opaque response - if (resource.match(/^https?:/)) { - request = fetch(resource, { mode: `no-cors` }) - } else { - request = fetch(resource) - } - - return request.then(response => cache.put(resource, response)) - }) - ) - ) - ) - } -}) +// noop From e02f9d54c05721fd96a8597954fc844d31386b8e Mon Sep 17 00:00:00 2001 From: David Bailey Date: Wed, 14 Nov 2018 14:21:13 +0000 Subject: [PATCH 16/21] minor fixes for things I copy-pasted wrong --- packages/gatsby-plugin-offline/src/gatsby-browser.js | 1 + packages/gatsby-plugin-offline/src/gatsby-node.js | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/gatsby-plugin-offline/src/gatsby-browser.js b/packages/gatsby-plugin-offline/src/gatsby-browser.js index 4f7beac2f9809..9f54f9808b2dd 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-browser.js +++ b/packages/gatsby-plugin-offline/src/gatsby-browser.js @@ -45,6 +45,7 @@ exports.onServiceWorkerActive = ({ const link = document.createElement(`link`) link.rel = `prefetch` link.href = resource + document.head.appendChild(link) link.onload = link.remove }) diff --git a/packages/gatsby-plugin-offline/src/gatsby-node.js b/packages/gatsby-plugin-offline/src/gatsby-node.js index c8b3520ebe254..1edc9a9b3a624 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-node.js +++ b/packages/gatsby-plugin-offline/src/gatsby-node.js @@ -102,6 +102,7 @@ exports.onPostBuild = (args, pluginOptions) => { { // Google Fonts CSS (doesn't end in .css so we need to specify it) urlPattern: /^https?:\/\/fonts\.googleapis\.com\/css/, + handler: `staleWhileRevalidate`, }, ], skipWaiting: true, From 0d0b001bebd20a1b7b7bf3911617f7b7631f18a9 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Thu, 15 Nov 2018 13:18:43 +0000 Subject: [PATCH 17/21] Fetch resources the same way in enqueue to getResourcesForPathname --- packages/gatsby/cache-dir/loader.js | 23 +++++-------- packages/gatsby/cache-dir/prefetch.js | 48 --------------------------- 2 files changed, 9 insertions(+), 62 deletions(-) delete mode 100644 packages/gatsby/cache-dir/prefetch.js diff --git a/packages/gatsby/cache-dir/loader.js b/packages/gatsby/cache-dir/loader.js index 67293bf8660e9..c9009119933db 100644 --- a/packages/gatsby/cache-dir/loader.js +++ b/packages/gatsby/cache-dir/loader.js @@ -1,6 +1,5 @@ import pageFinderFactory from "./find-page" import emitter from "./emitter" -import prefetchHelper from "./prefetch" const preferDefault = m => (m && m.default) || m @@ -106,15 +105,6 @@ const fetchResource = resourceName => { }) } -const prefetchResource = resourceName => { - if (resourceName.slice(0, 12) === `component---`) { - createComponentUrls(resourceName).forEach(url => prefetchHelper(url)) - } else { - const url = createJsonURL(jsonDataPaths[resourceName]) - prefetchHelper(url) - } -} - const getResourceModule = resourceName => fetchResource(resourceName).then(preferDefault) @@ -227,10 +217,15 @@ const queue = { } // Prefetch resources. - if (process.env.NODE_ENV === `production`) { - prefetchResource(page.jsonName) - prefetchResource(page.componentChunkName) - } + Promise.all([ + getResourceModule(page.componentChunkName), + getResourceModule(page.jsonName), + ]).then(([component, json]) => { + if (component && json) { + // Tell plugins the path has been successfully prefetched + onPostPrefetchPathname(path) + } + }) return true }, diff --git a/packages/gatsby/cache-dir/prefetch.js b/packages/gatsby/cache-dir/prefetch.js deleted file mode 100644 index 82c119ccb5a43..0000000000000 --- a/packages/gatsby/cache-dir/prefetch.js +++ /dev/null @@ -1,48 +0,0 @@ -const support = function(feature) { - if (typeof document === `undefined`) { - return false - } - const fakeLink = document.createElement(`link`) - try { - if (fakeLink.relList && typeof fakeLink.relList.supports === `function`) { - return fakeLink.relList.supports(feature) - } - } catch (err) { - return false - } - return false -} -const linkPrefetchStrategy = function(url) { - if (typeof document === `undefined`) { - return - } - const link = document.createElement(`link`) - link.setAttribute(`rel`, `prefetch`) - link.setAttribute(`href`, url) - const parentElement = - document.getElementsByTagName(`head`)[0] || - document.getElementsByName(`script`)[0].parentNode - parentElement.appendChild(link) -} -const xhrPrefetchStrategy = function(url) { - const req = new XMLHttpRequest() - req.open(`GET`, url, true) - req.withCredentials = true - req.send(null) -} - -const supportedPrefetchStrategy = support(`prefetch`) - ? linkPrefetchStrategy - : xhrPrefetchStrategy - -const preFetched = {} - -const prefetch = function(url) { - if (preFetched[url]) { - return - } - preFetched[url] = true - supportedPrefetchStrategy(url) -} - -export default prefetch From b9857c6ad3faccd3cb70f420328a49a25fb612cf Mon Sep 17 00:00:00 2001 From: David Bailey Date: Thu, 15 Nov 2018 13:46:31 +0000 Subject: [PATCH 18/21] Revert "Fetch resources the same way in enqueue to getResourcesForPathname" This reverts commit 0d0b001bebd20a1b7b7bf3911617f7b7631f18a9. --- packages/gatsby/cache-dir/loader.js | 23 ++++++++----- packages/gatsby/cache-dir/prefetch.js | 48 +++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 packages/gatsby/cache-dir/prefetch.js diff --git a/packages/gatsby/cache-dir/loader.js b/packages/gatsby/cache-dir/loader.js index c9009119933db..67293bf8660e9 100644 --- a/packages/gatsby/cache-dir/loader.js +++ b/packages/gatsby/cache-dir/loader.js @@ -1,5 +1,6 @@ import pageFinderFactory from "./find-page" import emitter from "./emitter" +import prefetchHelper from "./prefetch" const preferDefault = m => (m && m.default) || m @@ -105,6 +106,15 @@ const fetchResource = resourceName => { }) } +const prefetchResource = resourceName => { + if (resourceName.slice(0, 12) === `component---`) { + createComponentUrls(resourceName).forEach(url => prefetchHelper(url)) + } else { + const url = createJsonURL(jsonDataPaths[resourceName]) + prefetchHelper(url) + } +} + const getResourceModule = resourceName => fetchResource(resourceName).then(preferDefault) @@ -217,15 +227,10 @@ const queue = { } // Prefetch resources. - Promise.all([ - getResourceModule(page.componentChunkName), - getResourceModule(page.jsonName), - ]).then(([component, json]) => { - if (component && json) { - // Tell plugins the path has been successfully prefetched - onPostPrefetchPathname(path) - } - }) + if (process.env.NODE_ENV === `production`) { + prefetchResource(page.jsonName) + prefetchResource(page.componentChunkName) + } return true }, diff --git a/packages/gatsby/cache-dir/prefetch.js b/packages/gatsby/cache-dir/prefetch.js new file mode 100644 index 0000000000000..82c119ccb5a43 --- /dev/null +++ b/packages/gatsby/cache-dir/prefetch.js @@ -0,0 +1,48 @@ +const support = function(feature) { + if (typeof document === `undefined`) { + return false + } + const fakeLink = document.createElement(`link`) + try { + if (fakeLink.relList && typeof fakeLink.relList.supports === `function`) { + return fakeLink.relList.supports(feature) + } + } catch (err) { + return false + } + return false +} +const linkPrefetchStrategy = function(url) { + if (typeof document === `undefined`) { + return + } + const link = document.createElement(`link`) + link.setAttribute(`rel`, `prefetch`) + link.setAttribute(`href`, url) + const parentElement = + document.getElementsByTagName(`head`)[0] || + document.getElementsByName(`script`)[0].parentNode + parentElement.appendChild(link) +} +const xhrPrefetchStrategy = function(url) { + const req = new XMLHttpRequest() + req.open(`GET`, url, true) + req.withCredentials = true + req.send(null) +} + +const supportedPrefetchStrategy = support(`prefetch`) + ? linkPrefetchStrategy + : xhrPrefetchStrategy + +const preFetched = {} + +const prefetch = function(url) { + if (preFetched[url]) { + return + } + preFetched[url] = true + supportedPrefetchStrategy(url) +} + +export default prefetch From 6d6762c9c7a476e9f0b5dd147c3b0bfa857da2c8 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Thu, 15 Nov 2018 14:11:15 +0000 Subject: [PATCH 19/21] Refactor prefetching so we can detect success --- packages/gatsby/cache-dir/loader.js | 15 ++++-- packages/gatsby/cache-dir/prefetch.js | 67 +++++++++++++++++++-------- 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/packages/gatsby/cache-dir/loader.js b/packages/gatsby/cache-dir/loader.js index 67293bf8660e9..23a3dde924a7e 100644 --- a/packages/gatsby/cache-dir/loader.js +++ b/packages/gatsby/cache-dir/loader.js @@ -108,10 +108,12 @@ const fetchResource = resourceName => { const prefetchResource = resourceName => { if (resourceName.slice(0, 12) === `component---`) { - createComponentUrls(resourceName).forEach(url => prefetchHelper(url)) + return Promise.all( + createComponentUrls(resourceName).map(url => prefetchHelper(url)) + ) } else { const url = createJsonURL(jsonDataPaths[resourceName]) - prefetchHelper(url) + return prefetchHelper(url) } } @@ -228,8 +230,13 @@ const queue = { // Prefetch resources. if (process.env.NODE_ENV === `production`) { - prefetchResource(page.jsonName) - prefetchResource(page.componentChunkName) + Promise.all([ + prefetchResource(page.jsonName), + prefetchResource(page.componentChunkName), + ]).then(() => { + // Tell plugins the path has been successfully prefetched + onPostPrefetchPathname(path) + }) } return true diff --git a/packages/gatsby/cache-dir/prefetch.js b/packages/gatsby/cache-dir/prefetch.js index 82c119ccb5a43..1d6322d8aeeca 100644 --- a/packages/gatsby/cache-dir/prefetch.js +++ b/packages/gatsby/cache-dir/prefetch.js @@ -12,23 +12,44 @@ const support = function(feature) { } return false } + const linkPrefetchStrategy = function(url) { - if (typeof document === `undefined`) { - return - } - const link = document.createElement(`link`) - link.setAttribute(`rel`, `prefetch`) - link.setAttribute(`href`, url) - const parentElement = - document.getElementsByTagName(`head`)[0] || - document.getElementsByName(`script`)[0].parentNode - parentElement.appendChild(link) + return new Promise((resolve, reject) => { + if (typeof document === `undefined`) { + reject() + return + } + + const link = document.createElement(`link`) + link.setAttribute(`rel`, `prefetch`) + link.setAttribute(`href`, url) + + link.onload = resolve + link.onerror = reject + + const parentElement = + document.getElementsByTagName(`head`)[0] || + document.getElementsByName(`script`)[0].parentNode + parentElement.appendChild(link) + }) } + const xhrPrefetchStrategy = function(url) { - const req = new XMLHttpRequest() - req.open(`GET`, url, true) - req.withCredentials = true - req.send(null) + return new Promise((resolve, reject) => { + const req = new XMLHttpRequest() + req.open(`GET`, url, true) + req.withCredentials = true + + req.onload = () => { + if (req.status === 200) { + resolve() + } else { + reject() + } + } + + req.send(null) + }) } const supportedPrefetchStrategy = support(`prefetch`) @@ -38,11 +59,19 @@ const supportedPrefetchStrategy = support(`prefetch`) const preFetched = {} const prefetch = function(url) { - if (preFetched[url]) { - return - } - preFetched[url] = true - supportedPrefetchStrategy(url) + return new Promise(resolve => { + if (preFetched[url]) { + resolve() + return + } + + supportedPrefetchStrategy(url) + .then(() => { + resolve() + preFetched[url] = true + }) + .catch(() => {}) // 404s are logged to the console anyway + }) } export default prefetch From b7f8b8349a52dab780d5bc0ac0d0cea4e4394917 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Thu, 15 Nov 2018 14:20:33 +0000 Subject: [PATCH 20/21] Move catch to prevent onPostPrefetchPathname after failure --- packages/gatsby/cache-dir/loader.js | 13 +++++++++---- packages/gatsby/cache-dir/prefetch.js | 10 ++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/gatsby/cache-dir/loader.js b/packages/gatsby/cache-dir/loader.js index 23a3dde924a7e..91c005908ed88 100644 --- a/packages/gatsby/cache-dir/loader.js +++ b/packages/gatsby/cache-dir/loader.js @@ -233,10 +233,15 @@ const queue = { Promise.all([ prefetchResource(page.jsonName), prefetchResource(page.componentChunkName), - ]).then(() => { - // Tell plugins the path has been successfully prefetched - onPostPrefetchPathname(path) - }) + ]) + .then(() => { + // Tell plugins the path has been successfully prefetched + onPostPrefetchPathname(path) + }) + .catch(() => { + // Suppress additional console errors + // (404 errors are displayed anyway) + }) } return true diff --git a/packages/gatsby/cache-dir/prefetch.js b/packages/gatsby/cache-dir/prefetch.js index 1d6322d8aeeca..1775fe97e0a6e 100644 --- a/packages/gatsby/cache-dir/prefetch.js +++ b/packages/gatsby/cache-dir/prefetch.js @@ -65,12 +65,10 @@ const prefetch = function(url) { return } - supportedPrefetchStrategy(url) - .then(() => { - resolve() - preFetched[url] = true - }) - .catch(() => {}) // 404s are logged to the console anyway + supportedPrefetchStrategy(url).then(() => { + resolve() + preFetched[url] = true + }) }) } From 37034bc00bf9be05594bfd8361d7ba4537a0a283 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Thu, 15 Nov 2018 14:27:30 +0000 Subject: [PATCH 21/21] Revert "Move catch to prevent onPostPrefetchPathname after failure" This reverts commit b7f8b8349a52dab780d5bc0ac0d0cea4e4394917. --- packages/gatsby/cache-dir/loader.js | 13 ++++--------- packages/gatsby/cache-dir/prefetch.js | 10 ++++++---- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/packages/gatsby/cache-dir/loader.js b/packages/gatsby/cache-dir/loader.js index 91c005908ed88..23a3dde924a7e 100644 --- a/packages/gatsby/cache-dir/loader.js +++ b/packages/gatsby/cache-dir/loader.js @@ -233,15 +233,10 @@ const queue = { Promise.all([ prefetchResource(page.jsonName), prefetchResource(page.componentChunkName), - ]) - .then(() => { - // Tell plugins the path has been successfully prefetched - onPostPrefetchPathname(path) - }) - .catch(() => { - // Suppress additional console errors - // (404 errors are displayed anyway) - }) + ]).then(() => { + // Tell plugins the path has been successfully prefetched + onPostPrefetchPathname(path) + }) } return true diff --git a/packages/gatsby/cache-dir/prefetch.js b/packages/gatsby/cache-dir/prefetch.js index 1775fe97e0a6e..1d6322d8aeeca 100644 --- a/packages/gatsby/cache-dir/prefetch.js +++ b/packages/gatsby/cache-dir/prefetch.js @@ -65,10 +65,12 @@ const prefetch = function(url) { return } - supportedPrefetchStrategy(url).then(() => { - resolve() - preFetched[url] = true - }) + supportedPrefetchStrategy(url) + .then(() => { + resolve() + preFetched[url] = true + }) + .catch(() => {}) // 404s are logged to the console anyway }) }