refactor(pwa): ♻️ transform fetch Strategy into static only class
This commit is contained in:
parent
67e3330587
commit
96a4199fa2
|
|
@ -1,15 +1,21 @@
|
||||||
export class Strategy {
|
export class Strategy {
|
||||||
#cache: Cache
|
private constructor() {
|
||||||
|
throw new Error(
|
||||||
constructor(cache: Cache) {
|
'fetch Strategy is not instantiable and only expose static methods',
|
||||||
this.#cache = cache
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheFirst({ request, preloadResponse }: Pick<FetchEvent, 'request' | 'preloadResponse'>) {
|
static cacheFirst(
|
||||||
|
cache: Cache,
|
||||||
|
{ request, preloadResponse }: Pick<
|
||||||
|
FetchEvent,
|
||||||
|
'request' | 'preloadResponse'
|
||||||
|
>,
|
||||||
|
) {
|
||||||
const fetchRequest = async () => {
|
const fetchRequest = async () => {
|
||||||
const response = await fetch(request)
|
const response = await fetch(request)
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
this.#cache.put(request, response)
|
cache.put(request, response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -17,22 +23,26 @@ export class Strategy {
|
||||||
preloadResponse
|
preloadResponse
|
||||||
.then((preload: Response | undefined) => {
|
.then((preload: Response | undefined) => {
|
||||||
if (preload?.ok) {
|
if (preload?.ok) {
|
||||||
return this.#cache.put(request, preload)
|
return cache.put(request, preload)
|
||||||
}
|
}
|
||||||
throw new Error()
|
throw new Error()
|
||||||
})
|
})
|
||||||
// Else fetch request
|
// Else fetch request
|
||||||
.catch(fetchRequest)
|
.catch(fetchRequest)
|
||||||
|
|
||||||
return this.#cache.match(request)
|
return cache.match(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
fastestAndCacheRefresh(
|
static fastestAndCacheRefresh(
|
||||||
{ request, preloadResponse }: Pick<FetchEvent, 'request' | 'preloadResponse'>,
|
cache: Cache,
|
||||||
ac: AbortController = new AbortController()
|
{ request, preloadResponse }: Pick<
|
||||||
|
FetchEvent,
|
||||||
|
'request' | 'preloadResponse'
|
||||||
|
>,
|
||||||
|
ac: AbortController = new AbortController(),
|
||||||
) {
|
) {
|
||||||
// Get cache or throw
|
// Get cache or throw
|
||||||
const cachedOrError = this.#cache.match(request)
|
const cachedOrError = cache.match(request)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response) {
|
if (response) {
|
||||||
// Abort network request
|
// Abort network request
|
||||||
|
|
@ -43,12 +53,12 @@ export class Strategy {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Fetch and cache
|
// Fetch and cache
|
||||||
const fetchedAndCached = this.networkOnly({ request, preloadResponse}, ac)
|
const fetchedAndCached = this.networkOnly({ request, preloadResponse }, ac)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
// Abort cache request
|
// Abort cache request
|
||||||
ac.abort()
|
ac.abort()
|
||||||
// Update cache
|
// Update cache
|
||||||
this.#cache.put(request, response.clone())
|
cache.put(request, response.clone())
|
||||||
return response
|
return response
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -56,8 +66,12 @@ export class Strategy {
|
||||||
return Promise.race([cachedOrError, fetchedAndCached])
|
return Promise.race([cachedOrError, fetchedAndCached])
|
||||||
}
|
}
|
||||||
|
|
||||||
async networkFirst(
|
static async networkFirst(
|
||||||
{ request, preloadResponse }: Pick<FetchEvent, 'request' | 'preloadResponse'>,
|
cache: Cache,
|
||||||
|
{ request, preloadResponse }: Pick<
|
||||||
|
FetchEvent,
|
||||||
|
'request' | 'preloadResponse'
|
||||||
|
>,
|
||||||
{ fallbackUrl, timeout }: { fallbackUrl?: string; timeout?: number },
|
{ fallbackUrl, timeout }: { fallbackUrl?: string; timeout?: number },
|
||||||
) {
|
) {
|
||||||
const signal = timeout ? AbortSignal.timeout(timeout) : undefined
|
const signal = timeout ? AbortSignal.timeout(timeout) : undefined
|
||||||
|
|
@ -66,7 +80,7 @@ export class Strategy {
|
||||||
// Get navigator preload (see: https://developer.mozilla.org/en-US/docs/Web/API/Pick<FetchEvent, 'request' | 'preloadResponse'>/preloadResponse)
|
// Get navigator preload (see: https://developer.mozilla.org/en-US/docs/Web/API/Pick<FetchEvent, 'request' | 'preloadResponse'>/preloadResponse)
|
||||||
const preload = await getPreload(preloadResponse)
|
const preload = await getPreload(preloadResponse)
|
||||||
if (preload?.ok) {
|
if (preload?.ok) {
|
||||||
this.#cache.put(request, preload.clone())
|
cache.put(request, preload.clone())
|
||||||
return preload
|
return preload
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -74,23 +88,26 @@ export class Strategy {
|
||||||
// Else fetch request
|
// Else fetch request
|
||||||
const response = await fetch(request, { signal })
|
const response = await fetch(request, { signal })
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
this.#cache.put(request, response.clone())
|
cache.put(request, response.clone())
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Else return fallback or cached response
|
// Else return fallback or cached response
|
||||||
return this.#cache.match(fallbackUrl ?? request)
|
return cache.match(fallbackUrl ?? request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
networkOnly(
|
static networkOnly(
|
||||||
{ request, preloadResponse }: Pick<FetchEvent, 'request' | 'preloadResponse'>,
|
{ request, preloadResponse }: Pick<
|
||||||
ac: AbortController = new AbortController()
|
FetchEvent,
|
||||||
|
'request' | 'preloadResponse'
|
||||||
|
>,
|
||||||
|
ac: AbortController = new AbortController(),
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
// Browser preload
|
// Browser preload
|
||||||
const preload = getPreload(preloadResponse, ac)
|
const preload = getPreload(preloadResponse, ac)
|
||||||
.then(response => {
|
.then((response) => {
|
||||||
if (response === undefined) {
|
if (response === undefined) {
|
||||||
throw new Error(`no preload response for ${request.url}`)
|
throw new Error(`no preload response for ${request.url}`)
|
||||||
}
|
}
|
||||||
|
|
@ -101,13 +118,13 @@ export class Strategy {
|
||||||
|
|
||||||
// Client fetch
|
// Client fetch
|
||||||
const fetched = fetch(request, { signal: ac.signal })
|
const fetched = fetch(request, { signal: ac.signal })
|
||||||
.then(response => {
|
.then((response) => {
|
||||||
// Cancel preload event
|
// Cancel preload event
|
||||||
ac.abort()
|
ac.abort()
|
||||||
return response
|
return response
|
||||||
})
|
})
|
||||||
|
|
||||||
return Promise.race([preload, fetched])
|
return Promise.race([preload, fetched])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue