Skip to content

Commit

Permalink
Add Header Indicating Suspense Cache HIT
Browse files Browse the repository at this point in the history
  • Loading branch information
james-elicx committed May 15, 2024
1 parent 2d55e8f commit c24b3e0
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 12 deletions.
37 changes: 30 additions & 7 deletions packages/next-on-pages/templates/_worker.js/utils/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const NEXT_CACHE_SOFT_TAGS_HEADER = 'x-next-cache-soft-tags';

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

const CF_NEXT_SUSPENSE_CACHE_HEADER = 'cf-next-suspense-cache';

/**
* Handles an internal request to the suspense cache.
*
Expand Down Expand Up @@ -50,14 +52,17 @@ export async function handleSuspenseCacheRequest(request: Request) {
const data = await cache.get(cacheKey, { softTags });
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}`,
return new Response(
JSON.stringify(formatCacheValueForResponse(data.value)),
{
status: 200,
headers: {
'Content-Type': 'application/json',
'x-vercel-cache-state': 'fresh',
age: `${(Date.now() - (data.lastModified ?? Date.now())) / 1000}`,
},
},
});
);
}
case 'POST': {
// Retrieve request context.
Expand Down Expand Up @@ -124,3 +129,21 @@ async function getInternalCacheAdaptor(
function getTagsFromHeader(req: Request, key: string): string[] | undefined {
return req.headers.get(key)?.split(',')?.filter(Boolean);
}

function formatCacheValueForResponse(value: IncrementalCacheValue | null) {
switch (value?.kind) {
case 'FETCH':
return {
...value,
data: {
...value.data,
headers: {
...value.data.headers,
[CF_NEXT_SUSPENSE_CACHE_HEADER]: 'HIT',
},
},
};
default:
return value;
}
}
13 changes: 13 additions & 0 deletions pages-e2e/features/appFetchCache/assets/app/api/cache/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const runtime = 'edge';

export async function GET(request) {
const url = new URL('/api/hello', request.url);
const data = await fetch(url.href, { next: { tags: ['cache'] } });

return new Response(
JSON.stringify({
body: await data.text(),
headers: Object.fromEntries([...data.headers.entries()]),
}),
);
}
23 changes: 23 additions & 0 deletions pages-e2e/features/appFetchCache/fetch-cache.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { beforeAll, describe, it } from 'vitest';

describe('Simple Pages API Routes', () => {
it('should return a cached fetch response from the suspense cache', async ({
expect,
}) => {
const initialResp = await fetch(`${DEPLOYMENT_URL}/api/cache`);
const initialRespJson = await initialResp.json();

expect(initialRespJson.body).toEqual(expect.stringMatching('Hello world'));
expect(initialRespJson.headers).toEqual(
expect.not.objectContaining({ 'cf-next-suspense-cache': 'HIT' }),
);

const cachedResp = await fetch(`${DEPLOYMENT_URL}/api/cache`);
const cachedRespJson = await cachedResp.json();

expect(cachedRespJson.body).toEqual(expect.stringMatching('Hello world'));
expect(cachedRespJson.headers).toEqual(
expect.objectContaining({ 'cf-next-suspense-cache': 'HIT' }),
);
});
});
3 changes: 3 additions & 0 deletions pages-e2e/features/appFetchCache/main.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"setup": "node --loader tsm setup.ts"
}
2 changes: 2 additions & 0 deletions pages-e2e/features/appFetchCache/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { copyWorkspaceAssets } from '../_utils/copyWorkspaceAssets';
await copyWorkspaceAssets();
4 changes: 2 additions & 2 deletions pages-e2e/fixtures/app14.0.0/main.fixture
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
"compatibilityFlags": ["nodejs_compat"],
"kvNamespaces": {
"MY_KV": {
"production": {"id": "00000000000000000000000000000000"},
"staging": {"id": "00000000000000000000000000000000"}
"production": { "id": "00000000000000000000000000000000" },
"staging": { "id": "00000000000000000000000000000000" }
}
}
}
Expand Down
11 changes: 8 additions & 3 deletions pages-e2e/fixtures/appLatest/main.fixture
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"appConfigsRewritesRedirectsHeaders",
"appWasm",
"appServerActions",
"appGetRequestContext"
"appGetRequestContext",
"appFetchCache"
],
"localSetup": "./setup.sh",
"buildConfig": {
Expand All @@ -21,8 +22,12 @@
"compatibilityFlags": ["nodejs_compat"],
"kvNamespaces": {
"MY_KV": {
"production": {"id": "00000000000000000000000000000000"},
"staging": {"id": "00000000000000000000000000000000"}
"production": { "id": "00000000000000000000000000000000" },
"staging": { "id": "00000000000000000000000000000000" }
},
"__NEXT_ON_PAGES__KV_SUSPENSE_CACHE": {
"production": { "id": "00000000000000000000000000000000" },
"staging": { "id": "00000000000000000000000000000000" }
}
}
}
Expand Down

0 comments on commit c24b3e0

Please sign in to comment.