-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(strategy): new strategies + cleanup
- Loading branch information
Showing
5 changed files
with
143 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import type { RemixCache } from '@remix-pwa/cache'; | ||
import { Storage, createCache } from '@remix-pwa/cache'; | ||
|
||
import type { StrategyOptions, StrategyResponse } from './types.js'; | ||
import { isHttpRequest } from './utils.js'; | ||
|
||
export interface CacheFirstStrategyOptions extends StrategyOptions { | ||
/** | ||
* A callback that will be called when the network request fails before | ||
* an attempt is made to retrieve from the cache. This is useful for stuffs like | ||
* logging errors and queueing requests. | ||
* | ||
* Defaults to `undefined` | ||
*/ | ||
fetchDidFail?: (() => void | (() => Promise<void>))[] | undefined; | ||
} | ||
|
||
export const cacheFirst = async ({ | ||
cache: cacheName, | ||
cacheOptions, | ||
fetchDidFail = undefined, | ||
}: CacheFirstStrategyOptions): Promise<StrategyResponse> => { | ||
return async (request: Request | URL) => { | ||
if (!isHttpRequest(request)) { | ||
return new Response('Not a HTTP request', { status: 403 }); | ||
} | ||
|
||
let remixCache: RemixCache; | ||
|
||
if (typeof cacheName === 'string') { | ||
Storage.init(); | ||
remixCache = Storage.has(cacheName) | ||
? (Storage.get(cacheName) as RemixCache) | ||
: createCache({ name: cacheName, ...cacheOptions }); | ||
} else { | ||
Storage.init(); | ||
remixCache = cacheName; | ||
} | ||
|
||
const response = await remixCache.match(request); | ||
|
||
if (!response) { | ||
try { | ||
const networkResponse = await fetch(request); | ||
|
||
remixCache.put(request, networkResponse.clone()); | ||
|
||
return networkResponse; | ||
} catch (err) { | ||
if (fetchDidFail) { | ||
await Promise.all(fetchDidFail.map(cb => cb())); | ||
} | ||
|
||
throw err; | ||
} | ||
} | ||
|
||
return response; | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import type { RemixCache } from '@remix-pwa/cache'; | ||
import { Storage, createCache } from '@remix-pwa/cache'; | ||
|
||
import type { StrategyOptions, StrategyResponse } from './types.js'; | ||
import { isHttpRequest } from './utils.js'; | ||
|
||
export interface StaleWhileRevalidateStrategyOptions extends StrategyOptions { | ||
/** | ||
* A callback that will be called when the network request fails before | ||
* an attempt is made to retrieve from the cache. This is useful for stuffs like | ||
* logging errors and queueing requests. | ||
* | ||
* Defaults to `undefined` | ||
*/ | ||
fetchDidFail?: (() => void | (() => Promise<void>))[] | undefined; | ||
} | ||
|
||
export const staleWhileRevalidate = async ({ | ||
cache: cacheName, | ||
cacheOptions, | ||
fetchDidFail = undefined, | ||
}: StaleWhileRevalidateStrategyOptions): Promise<StrategyResponse> => { | ||
return async (request: Request | URL) => { | ||
if (!isHttpRequest(request)) { | ||
return new Response('Not a HTTP request', { status: 403 }); | ||
} | ||
|
||
let remixCache: RemixCache; | ||
|
||
if (typeof cacheName === 'string') { | ||
Storage.init(); | ||
remixCache = Storage.has(cacheName) | ||
? (Storage.get(cacheName) as RemixCache) | ||
: createCache({ name: cacheName, ...cacheOptions }); | ||
} else { | ||
Storage.init(); | ||
remixCache = cacheName; | ||
} | ||
|
||
return remixCache.match(request).then(async response => { | ||
const fetchPromise = fetch(request) | ||
.then(async networkResponse => { | ||
await remixCache.put(request, networkResponse.clone()); | ||
|
||
return networkResponse; | ||
}) | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
.catch(async _err => { | ||
if (fetchDidFail) { | ||
await Promise.all(fetchDidFail.map(cb => cb())); | ||
} | ||
|
||
return new Response(JSON.stringify({ error: 'Network request failed' }), { | ||
status: 500, | ||
statusText: 'Network request failed', | ||
}); | ||
}); | ||
|
||
return response || fetchPromise; | ||
}); | ||
}; | ||
}; | ||
|
||
export const swr = staleWhileRevalidate; |