From de089aa429f4f2b8de89ea3faca33230b7e3c22a Mon Sep 17 00:00:00 2001 From: keyan Date: Sat, 29 Jul 2023 14:33:19 -0500 Subject: [PATCH] service worker enhancements --- next.config.js | 35 +++++++++++++++++++++++++---------- sw/build.js | 1 - sw/index.js | 24 ++++++++++++++++++++---- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/next.config.js b/next.config.js index a28f6b62..a32dd4bd 100644 --- a/next.config.js +++ b/next.config.js @@ -136,19 +136,34 @@ module.exports = withPlausibleProxy()({ } ] }, - webpack: (config, { isServer }) => { + webpack: (config, { isServer, dev }) => { if (isServer) { generatePrecacheManifest() - config.plugins.push( - new InjectManifest({ - // ignore the precached manifest which includes the webpack assets - // since they are not useful to us - exclude: [/.*/], - // by default, webpack saves service worker at .next/server/ - swDest: '../../public/sw.js', - swSrc: './sw/index.js' + const workboxPlugin = new InjectManifest({ + // ignore the precached manifest which includes the webpack assets + // since they are not useful to us + exclude: [/.*/], + // by default, webpack saves service worker at .next/server/ + swDest: '../../public/sw.js', + swSrc: './sw/index.js' + }) + if (dev) { + // Suppress the "InjectManifest has been called multiple times" warning by reaching into + // the private properties of the plugin and making sure it never ends up in the state + // where it makes that warning. + // https://github.com/GoogleChrome/workbox/blob/v6/packages/workbox-webpack-plugin/src/inject-manifest.ts#L260-L282 + Object.defineProperty(workboxPlugin, 'alreadyCalled', { + get () { + return false + }, + set () { + // do nothing; the internals try to set it to true, which then results in a warning + // on the next run of webpack. + } }) - ) + } + + config.plugins.push(workboxPlugin) } return config } diff --git a/sw/build.js b/sw/build.js index 9908040a..b61b7485 100644 --- a/sw/build.js +++ b/sw/build.js @@ -32,7 +32,6 @@ function generatePrecacheManifest () { const staticDir = join(__dirname, '../public') const staticFiles = walkSync(staticDir) - console.log(staticFiles) const staticMatch = f => [/\.(gif|jpe?g|ico|png|ttf|woff|woff2|webmanifest)$/].some(m => m.test(f)) staticFiles.filter(staticMatch).forEach(file => { const stats = statSync(file) diff --git a/sw/index.js b/sw/index.js index 1327e0d8..c8796442 100644 --- a/sw/index.js +++ b/sw/index.js @@ -3,11 +3,20 @@ import { precacheAndRoute } from 'workbox-precaching' import { offlineFallback } from 'workbox-recipes' import { setDefaultHandler } from 'workbox-routing' import { NetworkOnly } from 'workbox-strategies' +import { enable } from 'workbox-navigation-preload' import manifest from './precache-manifest.json' +// preloading improves startup performance +// https://developer.chrome.com/docs/workbox/modules/workbox-navigation-preload/ +enable() + +// uncomment to disable workbox console logs +// self.__WB_DISABLE_DEV_LOGS = true + // ignore precache manifest generated by InjectManifest // they statically check for the presence of this variable console.log(self.__WB_MANIFEST) + precacheAndRoute(manifest) self.addEventListener('install', () => { @@ -18,7 +27,14 @@ self.addEventListener('install', () => { // to the browser as if the service worker wouldn't exist. // The browser may use own caching (HTTP cache). // Also, the offline fallback only works if request matched a route -setDefaultHandler(new NetworkOnly()) +setDefaultHandler(new NetworkOnly({ + // tell us why a request failed in dev + plugins: [{ + fetchDidFail: async (args) => { + process.env.NODE_ENV !== 'production' && console.log('fetch did fail', ...args) + } + }] +})) // This won't work in dev because pages are never cached. // See https://github.com/vercel/next.js/blob/337fb6a9aadb61c916f0121c899e463819cd3f33/server/render.js#L181-L185 @@ -72,6 +88,7 @@ self.addEventListener('pushsubscriptionchange', (event) => { id } }` + const subscription = self.registration.pushManager .subscribe(event.oldSubscription.options) .then((subscription) => { @@ -92,7 +109,6 @@ self.addEventListener('pushsubscriptionchange', (event) => { body }) }) + event.waitUntil(subscription) -}, -false -) +}, false)