Reputation: 11
I was using workbox5.14 (@nuxtjs/pwa) to precache the 'message' event by passing the URL to PrecacheController when received. (from workbox-window) At this time, PrecacheController.addToCacheList() would not execute the cache, and for some reason PrecacheController.install() would do so.
However, with v6, PrecacheController.install() now requires an 'install' event or an 'activate' event, and I cannot execute PrecacheController.install(event) with a 'message' event. This results in an error. "sw.js:238 Uncaught (in promise) DOMException: Failed to execute 'waitUntil' on 'ExtendableEvent': The event handler is already finished and no extend lifetime promises are outstanding."
How can we execute PrecacheController's caching process on the 'message' event?
Library Affected: workbox-precaching
Browser & Platform: Google Chrome 106.0.5249.103(Official Build)
Issue or Feature Request Description: v5 ok
/* global importScripts, workbox, consola, processFuncPromise */
const cacheName = workbox.core.cacheNames.precache
const precacheController = new workbox.precaching.PrecacheController(cacheName)
addEventListener('message', async (event) => {
if (event.data.type === 'ADD_PRECACHE') {
const cacheTargetFiles = event.data.payload
const addCaches = async (cacheTargetFiles) => {
for (const file of cacheTargetFiles) {
const cacheKey = precacheController.getCacheKeyForURL(file.filePath)
const cached = await caches
.match(cacheKey)
.then((response) => response !== undefined)
if (!cached) {
precacheController.addToCacheList([{ url: file.filePath, revision: file.revision }])
}
}
}
const checkCaches = async () => {
const cachedList = cacheTargetFiles.map(async (file) => {
const cacheKey = precacheController.getCacheKeyForURL(file.filePath)
const cached = await caches
.match(cacheKey)
.then((response) => response !== undefined)
return cached
})
const cachedListResult = await Promise.all(cachedList)
const cachedListResultFilterd = cachedListResult.filter((response) => {
return response
})
if (cachedListResultFilterd.length === cacheTargetFiles.length) {
return Promise.resolve({ isCompleted: true })
} else {
return Promise.resolve(null)
}
}
await addCaches(cacheTargetFiles)
// ★Caching is started with this INSTALL
precacheController.install()
await processFuncPromise(checkCaches)
self.clients.matchAll().then((clients) =>
clients.forEach((client) => {
client.postMessage({ type: 'FINISHED_ADD_PRECACHE' })
})
)
}
})
addEventListener('install', (event) => {
event.waitUntil(precacheController.install())
event.waitUntil(self.skipWaiting())
})
addEventListener('activate', (event) => {
workbox.precaching.cleanupOutdatedCaches()
event.waitUntil(precacheController.activate())
event.waitUntil(self.clients.claim())
})
addEventListener('fetch', (event) => {
const cacheKey = precacheController.getCacheKeyForURL(event.request.url)
event.respondWith(
caches.match(cacheKey).then(function (response) {
// Cache hit - return the response from the cached version
if (response) {
return response
}
// Not in cache - return the result from the live server
// `fetch` is essentially a "fallback"
return fetch(event.request)
})
)
})
// ↓processFuncPromise()
// export const processFuncPromise = (func, interval = 500) => {
// const retryFunc = (resolve, reject) =>
// func()
// .then((result) => ({ result, isCompleted: result !== null }))
// .then(({ result, isCompleted }) => {
// if (isCompleted) {
// return resolve(result)
// } else {
// return setTimeout(() => retryFunc(resolve, reject), interval)
// }
// })
// .catch(reject)
// return new Promise(retryFunc)
// }
v6 ng
/* global importScripts, workbox, consola, processFuncPromise */
const cacheName = workbox.core.cacheNames.precache
const precacheController = new workbox.precaching.PrecacheController(cacheName)
addEventListener('message', async (event) => {
if (event.data.type === 'ADD_PRECACHE') {
const cacheTargetFiles = event.data.payload
const addCaches = async (cacheTargetFiles) => {
for (const file of cacheTargetFiles) {
const cacheKey = precacheController.getCacheKeyForURL(file.filePath)
const cached = await caches
.match(cacheKey)
.then((response) => response !== undefined)
if (!cached) {
precacheController.addToCacheList([{ url: file.filePath, revision: file.revision }])
}
}
}
const checkCaches = async () => {
const cachedList = cacheTargetFiles.map(async (file) => {
const cacheKey = precacheController.getCacheKeyForURL(file.filePath)
const cached = await caches
.match(cacheKey)
.then((response) => response !== undefined)
return cached
})
const cachedListResult = await Promise.all(cachedList)
const cachedListResultFilterd = cachedListResult.filter((response) => {
return response
})
if (cachedListResultFilterd.length === cacheTargetFiles.length) {
return Promise.resolve({ isCompleted: true })
} else {
return Promise.resolve(null)
}
}
await addCaches(cacheTargetFiles)
// ★ERROR
precacheController.install(event)
await processFuncPromise(checkCaches)
self.clients.matchAll().then((clients) =>
clients.forEach((client) => {
client.postMessage({ type: 'FINISHED_ADD_PRECACHE' })
})
)
}
})
addEventListener('install', (event) => {
precacheController.install(event)
event.waitUntil(self.skipWaiting())
})
addEventListener('activate', (event) => {
workbox.precaching.cleanupOutdatedCaches()
precacheController.activate(event)
event.waitUntil(self.clients.claim())
})
addEventListener('fetch', (event) => {
const cacheKey = precacheController.getCacheKeyForURL(event.request.url)
event.respondWith(
caches.match(cacheKey).then(function (response) {
// Cache hit - return the response from the cached version
if (response) {
return response
}
// Not in cache - return the result from the live server
// `fetch` is essentially a "fallback"
return fetch(event.request)
})
)
})
// ↓processFuncPromise()
// export const processFuncPromise = (func, interval = 500) => {
// const retryFunc = (resolve, reject) =>
// func()
// .then((result) => ({ result, isCompleted: result !== null }))
// .then(({ result, isCompleted }) => {
// if (isCompleted) {
// return resolve(result)
// } else {
// return setTimeout(() => retryFunc(resolve, reject), interval)
// }
// })
// .catch(reject)
// return new Promise(retryFunc)
// }
I asked the question on githubbut could not get an answer, so I came here.
Upvotes: 1
Views: 326