-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: fetch (suspense) cache handling, and
next/cache
support (#419)
* feat: fetch (suspense) cache handling, and `next/cache` support * fix tag revalidation + stale entry revalidation * D1 and R2 cache interfaces * docs * Apply suggestions from code review Co-authored-by: Dario Piotrowicz <[email protected]> * commit desktop changes so i can move to my laptop * done i think? * docs * comment * *smashes keyboard against head* * Update packages/next-on-pages/templates/cache/interface.ts Co-authored-by: Dario Piotrowicz <[email protected]> * add `.local` to hostname * apply suggestions + tweaks * Apply suggestions from code review Co-authored-by: Dario Piotrowicz <[email protected]> * dario broke prettier --------- Co-authored-by: Dario Piotrowicz <[email protected]>
- Loading branch information
1 parent
4570aa6
commit 291bfde
Showing
11 changed files
with
407 additions
and
16 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,5 @@ | ||
--- | ||
'@cloudflare/next-on-pages': patch | ||
--- | ||
|
||
Stop the `cache` property in fetch requests causing internal server error. |
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,5 @@ | ||
--- | ||
'@cloudflare/next-on-pages': minor | ||
--- | ||
|
||
Support for the internal fetch (suspense) cache, and `next/cache` data revalidation. |
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,15 @@ | ||
# Caching and Data Revalidation | ||
|
||
`@cloudflare/next-on-pages` comes with support for data revalidation and caching for fetch requests. This is done in our router and acts as an extension to Next.js' built-in functionality. | ||
|
||
## Storage Options | ||
|
||
There are various different bindings and storage options that one could use for caching. At the moment, `@cloudflare/next-on-pages` supports the Cache API out-of-the-box. | ||
|
||
In the future, support will be available for creating custom cache interfaces and using different bindings. | ||
|
||
### Cache API | ||
|
||
The [Cache API](https://developers.cloudflare.com/workers/runtime-apis/cache/) is a per data-center cache that is ideal for storing data that is not required to be accessible globally. It is worth noting that Vercel's Data Cache is regional, like with the Cache API, so there is no difference in terms of data availability. | ||
|
||
Due to how the Cache API works, you need to be using a domain for your deployment for it to take effect. |
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
76 changes: 76 additions & 0 deletions
76
packages/next-on-pages/templates/_worker.js/utils/cache.ts
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,76 @@ | ||
import type { CacheAdaptor, IncrementalCacheValue } from '../../cache'; | ||
import { SUSPENSE_CACHE_URL } from '../../cache'; | ||
import { CacheApiAdaptor } from '../../cache/cache-api'; | ||
|
||
/** | ||
* Handles an internal request to the suspense cache. | ||
* | ||
* @param request Incoming request to handle. | ||
* @returns Response to the request, or null if the request is not for the suspense cache. | ||
*/ | ||
export async function handleSuspenseCacheRequest(request: Request) { | ||
const baseUrl = `https://${SUSPENSE_CACHE_URL}/v1/suspense-cache/`; | ||
if (!request.url.startsWith(baseUrl)) return null; | ||
|
||
try { | ||
const url = new URL(request.url); | ||
const cache = await getSuspenseCacheAdaptor(); | ||
|
||
if (url.pathname === '/v1/suspense-cache/revalidate') { | ||
// Update the revalidated timestamp for the tags in the tags manifest. | ||
const tags = url.searchParams.get('tags')?.split(',') ?? []; | ||
|
||
for (const tag of tags) { | ||
await cache.revalidateTag(tag); | ||
} | ||
|
||
return new Response(null, { status: 200 }); | ||
} | ||
|
||
// Extract the cache key from the URL. | ||
const cacheKey = url.pathname.replace('/v1/suspense-cache/', ''); | ||
if (!cacheKey.length) { | ||
return new Response('Invalid cache key', { status: 400 }); | ||
} | ||
|
||
switch (request.method) { | ||
case 'GET': { | ||
// Retrieve the value from the cache. | ||
const data = await cache.get(cacheKey); | ||
if (!data) return new Response(null, { status: 404 }); | ||
|
||
return new Response(JSON.stringify(data.value), { | ||
status: 200, | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'x-vercel-cache-state': 'fresh', | ||
age: `${(Date.now() - (data.lastModified ?? Date.now())) / 1000}`, | ||
}, | ||
}); | ||
} | ||
case 'POST': { | ||
// Update the value in the cache. | ||
const body = await request.json<IncrementalCacheValue>(); | ||
await cache.set(cacheKey, body); | ||
|
||
return new Response(null, { status: 200 }); | ||
} | ||
default: | ||
return new Response(null, { status: 405 }); | ||
} | ||
} catch (e) { | ||
// eslint-disable-next-line no-console | ||
console.error(e); | ||
return new Response('Error handling cache request', { status: 500 }); | ||
} | ||
} | ||
|
||
/** | ||
* Gets the cache adaptor to use for the suspense cache. | ||
* | ||
* @returns Adaptor for the suspense cache. | ||
*/ | ||
export async function getSuspenseCacheAdaptor(): Promise<CacheAdaptor> { | ||
// TODO: Try to lazy import the custom cache adaptor. | ||
return new CacheApiAdaptor(); | ||
} |
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
Oops, something went wrong.