feat(pwa): add service worker cache strategies

This commit is contained in:
Julien Oculi 2024-06-13 12:28:27 +02:00
parent 61d072cb06
commit 908c820cb0

View file

@ -0,0 +1,74 @@
export class Strategy {
#cache: Cache
constructor(cache: Cache) {
this.#cache = cache
}
cacheFirst({ request, preloadResponse }: FetchEvent) {
const fetchRequest = async () => {
const response = await fetch(request)
if (response.ok) {
this.#cache.put(request, response)
}
}
// Get navigator preload request
preloadResponse
.then((preload: Response | undefined) => {
if (preload?.ok) {
return this.#cache.put(request, preload)
}
throw new Error()
})
// Else fetch request
.catch(fetchRequest)
return this.#cache.match(request)
}
async networkFirst(
{ request, preloadResponse }: FetchEvent,
{ fallbackUrl, timeout }: { fallbackUrl?: string; timeout?: number },
) {
const signal = timeout ? AbortSignal.timeout(timeout) : undefined
try {
// Get navigator preload (see: https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/preloadResponse)
const preload = await getPreload(preloadResponse)
if (preload?.ok) {
this.#cache.put(request, preload.clone())
return preload
}
} catch {
try {
// Else fetch request
const response = await fetch(request, { signal })
if (response.ok) {
this.#cache.put(request, response.clone())
return response
}
} catch {
// Else return fallback or cached response
return this.#cache.match(fallbackUrl ?? request)
}
}
}
}
function getPreload(
preloadResponse: FetchEvent['preloadResponse'],
ac?: { signal?: AbortSignal },
): Promise<Response | undefined> {
const { promise, resolve, reject } = Promise.withResolvers<
Response | undefined
>()
ac?.signal?.addEventListener('abort', () => {
reject(new Error('aborted by signal'))
})
resolve(preloadResponse)
return promise
}