Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 16ee6d4

Browse files
committedMay 15, 2024·
Add Header Indicating Suspense Cache HIT
1 parent 2d55e8f commit 16ee6d4

File tree

8 files changed

+96
-15
lines changed

8 files changed

+96
-15
lines changed
 

‎packages/next-on-pages/templates/_worker.js/utils/cache.ts

+30-7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ const NEXT_CACHE_SOFT_TAGS_HEADER = 'x-next-cache-soft-tags';
88

99
const REQUEST_CONTEXT_KEY = Symbol.for('__cloudflare-request-context__');
1010

11+
const CF_NEXT_SUSPENSE_CACHE_HEADER = 'cf-next-suspense-cache';
12+
1113
/**
1214
* Handles an internal request to the suspense cache.
1315
*
@@ -50,14 +52,17 @@ export async function handleSuspenseCacheRequest(request: Request) {
5052
const data = await cache.get(cacheKey, { softTags });
5153
if (!data) return new Response(null, { status: 404 });
5254

53-
return new Response(JSON.stringify(data.value), {
54-
status: 200,
55-
headers: {
56-
'Content-Type': 'application/json',
57-
'x-vercel-cache-state': 'fresh',
58-
age: `${(Date.now() - (data.lastModified ?? Date.now())) / 1000}`,
55+
return new Response(
56+
JSON.stringify(formatCacheValueForResponse(data.value)),
57+
{
58+
status: 200,
59+
headers: {
60+
'Content-Type': 'application/json',
61+
'x-vercel-cache-state': 'fresh',
62+
age: `${(Date.now() - (data.lastModified ?? Date.now())) / 1000}`,
63+
},
5964
},
60-
});
65+
);
6166
}
6267
case 'POST': {
6368
// Retrieve request context.
@@ -124,3 +129,21 @@ async function getInternalCacheAdaptor(
124129
function getTagsFromHeader(req: Request, key: string): string[] | undefined {
125130
return req.headers.get(key)?.split(',')?.filter(Boolean);
126131
}
132+
133+
function formatCacheValueForResponse(value: IncrementalCacheValue | null) {
134+
switch (value?.kind) {
135+
case 'FETCH':
136+
return {
137+
...value,
138+
data: {
139+
...value.data,
140+
headers: {
141+
...value.data.headers,
142+
[CF_NEXT_SUSPENSE_CACHE_HEADER]: 'HIT',
143+
},
144+
},
145+
};
146+
default:
147+
return value;
148+
}
149+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export const runtime = 'edge';
2+
3+
export async function GET(request) {
4+
const url = new URL('/api/hello', request.url);
5+
const data = await fetch(url.href, { next: { tags: ['cache'] } });
6+
7+
return new Response(
8+
JSON.stringify({
9+
body: await data.text(),
10+
headers: Object.fromEntries([...data.headers.entries()]),
11+
}),
12+
);
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { beforeAll, describe, it } from 'vitest';
2+
3+
describe('Simple Pages API Routes', () => {
4+
it('should return a cached fetch response from the suspense cache', async ({
5+
expect,
6+
}) => {
7+
const initialResp = await fetch(`${DEPLOYMENT_URL}/api/cache`);
8+
const initialRespJson = await initialResp.json();
9+
10+
expect(initialRespJson.body).toEqual(expect.stringMatching('Hello world'));
11+
expect(initialRespJson.headers).toEqual(
12+
expect.not.objectContaining({ 'cf-next-suspense-cache': 'HIT' }),
13+
);
14+
15+
const cachedResp = await fetch(`${DEPLOYMENT_URL}/api/cache`);
16+
const cachedRespJson = await cachedResp.json();
17+
18+
expect(cachedRespJson.body).toEqual(expect.stringMatching('Hello world'));
19+
expect(cachedRespJson.headers).toEqual(
20+
expect.objectContaining({ 'cf-next-suspense-cache': 'HIT' }),
21+
);
22+
});
23+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"setup": "node --loader tsm setup.ts"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { copyWorkspaceAssets } from '../_utils/copyWorkspaceAssets';
2+
await copyWorkspaceAssets();

‎pages-e2e/fixtures/app13.4.0/main.fixture

+9-2
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,21 @@
88
"appConfigsTrailingSlashFalse",
99
"appConfigsRewritesRedirectsHeaders",
1010
"appWasm",
11-
"appGetRequestContext"
11+
"appGetRequestContext",
12+
"appFetchCache"
1213
],
1314
"localSetup": "npm install",
1415
"buildConfig": {
1516
"buildCommand": "npx --force ../../../packages/next-on-pages",
1617
"buildOutputDirectory": ".vercel/output/static"
1718
},
1819
"deploymentConfig": {
19-
"compatibilityFlags": ["nodejs_compat"]
20+
"compatibilityFlags": ["nodejs_compat"],
21+
"kvNamespaces": {
22+
"__NEXT_ON_PAGES__KV_SUSPENSE_CACHE": {
23+
"production": { "id": "00000000000000000000000000000000" },
24+
"staging": { "id": "00000000000000000000000000000000" }
25+
}
26+
}
2027
}
2128
}

‎pages-e2e/fixtures/app14.0.0/main.fixture

+8-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"appConfigsTrailingSlashTrue",
66
"appWasm",
77
"appServerActions",
8-
"appGetRequestContext"
8+
"appGetRequestContext",
9+
"appFetchCache"
910
],
1011
"localSetup": "npm install",
1112
"buildConfig": {
@@ -16,8 +17,12 @@
1617
"compatibilityFlags": ["nodejs_compat"],
1718
"kvNamespaces": {
1819
"MY_KV": {
19-
"production": {"id": "00000000000000000000000000000000"},
20-
"staging": {"id": "00000000000000000000000000000000"}
20+
"production": { "id": "00000000000000000000000000000000" },
21+
"staging": { "id": "00000000000000000000000000000000" }
22+
},
23+
"__NEXT_ON_PAGES__KV_SUSPENSE_CACHE": {
24+
"production": { "id": "00000000000000000000000000000000" },
25+
"staging": { "id": "00000000000000000000000000000000" }
2126
}
2227
}
2328
}

‎pages-e2e/fixtures/appLatest/main.fixture

+8-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"appConfigsRewritesRedirectsHeaders",
1111
"appWasm",
1212
"appServerActions",
13-
"appGetRequestContext"
13+
"appGetRequestContext",
14+
"appFetchCache"
1415
],
1516
"localSetup": "./setup.sh",
1617
"buildConfig": {
@@ -21,8 +22,12 @@
2122
"compatibilityFlags": ["nodejs_compat"],
2223
"kvNamespaces": {
2324
"MY_KV": {
24-
"production": {"id": "00000000000000000000000000000000"},
25-
"staging": {"id": "00000000000000000000000000000000"}
25+
"production": { "id": "00000000000000000000000000000000" },
26+
"staging": { "id": "00000000000000000000000000000000" }
27+
},
28+
"__NEXT_ON_PAGES__KV_SUSPENSE_CACHE": {
29+
"production": { "id": "00000000000000000000000000000000" },
30+
"staging": { "id": "00000000000000000000000000000000" }
2631
}
2732
}
2833
}

0 commit comments

Comments
 (0)
Please sign in to comment.