From 7c826a17219053421a85a75038474843f581e026 Mon Sep 17 00:00:00 2001 From: David Bailey <4248177+davidbailey00@users.noreply.github.com> Date: Wed, 14 Nov 2018 20:22:14 +0000 Subject: [PATCH] fix(gatsby-plugin-offline): fix certain resources being cached excessively (#9923) Fixes #9415 This PR leverages Workbox's automatic caching when a resource is fetched, by creating a `` prefetch element for each resource. This means we don't have to worry about whether the resource can be fetched with CORS or not, since the browser handles it automatically. I've also changed the runtime caching RegExps so that only paths with certain extensions are cached, but 3rd party resources with these extensions can now be cached. --- packages/gatsby-plugin-offline/README.md | 21 ++++++++----- .../src/gatsby-browser.js | 19 ++++++++---- .../gatsby-plugin-offline/src/gatsby-node.js | 21 ++++++++----- .../gatsby-plugin-offline/src/sw-append.js | 30 +------------------ 4 files changed, 42 insertions(+), 49 deletions(-) diff --git a/packages/gatsby-plugin-offline/README.md b/packages/gatsby-plugin-offline/README.md index 09493aff2882e..809cc3b41db64 100644 --- a/packages/gatsby-plugin-offline/README.md +++ b/packages/gatsby-plugin-offline/README.md @@ -49,18 +49,25 @@ const options = { 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\/)/, + // Don't cache-bust JS or CSS files, and anything in the static directory, + // since these files have unique URLs and their contents will never change + dontCacheBustUrlsMatching: /(\.js$|\.css$|\/static\/)/, runtimeCaching: [ { - // Add runtime caching of various page resources. - urlPattern: /\.(?:png|jpg|jpeg|webp|svg|gif|tiff|js|woff|woff2|json|css)$/, + // Use cacheFirst since these don't need to be revalidated (same RegExp + // and same reason as above) + urlPattern: /(\.js$|\.css$|\/static\/)/, + handler: `cacheFirst`, + }, + { + // Add runtime caching of various other page resources + 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/, + handler: `staleWhileRevalidate`, }, ], skipWaiting: true, diff --git a/packages/gatsby-plugin-offline/src/gatsby-browser.js b/packages/gatsby-plugin-offline/src/gatsby-browser.js index 318efddceac57..0f5749e483eb9 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,16 @@ 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 + + link.onload = link.remove + link.onerror = link.remove + + document.head.appendChild(link) }) } diff --git a/packages/gatsby-plugin-offline/src/gatsby-node.js b/packages/gatsby-plugin-offline/src/gatsby-node.js index a9f4419e93d21..892e99eb953dc 100644 --- a/packages/gatsby-plugin-offline/src/gatsby-node.js +++ b/packages/gatsby-plugin-offline/src/gatsby-node.js @@ -91,18 +91,25 @@ exports.onPostBuild = (args, pluginOptions) => { 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\/)/, + // Don't cache-bust JS or CSS files, and anything in the static directory, + // since these files have unique URLs and their contents will never change + dontCacheBustUrlsMatching: /(\.js$|\.css$|\/static\/)/, runtimeCaching: [ { - // Add runtime caching of various page resources. - urlPattern: /\.(?:png|jpg|jpeg|webp|svg|gif|tiff|js|woff|woff2|json|css)$/, + // Use cacheFirst since these don't need to be revalidated (same RegExp + // and same reason as above) + urlPattern: /(\.js$|\.css$|\/static\/)/, + handler: `cacheFirst`, + }, + { + // Add runtime caching of various other page resources + 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/, + handler: `staleWhileRevalidate`, }, ], 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