Skip to content

Commit 1220e04

Browse files
authoredDec 1, 2023
fix: standardize stale-while-revalidate header (#95)
* fix: next.js doesn't respect swr standard * chore: add test for swr fix * chore: update tests with new swr value
1 parent a0c93ca commit 1220e04

File tree

5 files changed

+30
-13
lines changed

5 files changed

+30
-13
lines changed
 

‎src/run/headers.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,20 @@ const getHeaderValueArray = (header: string): string[] => {
2525
return header.split(',').map((value) => value.trim())
2626
}
2727

28-
const removeHeaderValues = (header: string, values: string[]): string => {
28+
const omitHeaderValues = (header: string, values: string[]): string => {
2929
const headerValues = getHeaderValueArray(header)
3030
const filteredValues = headerValues.filter(
3131
(value) => !values.some((val) => value.startsWith(val)),
3232
)
3333
return filteredValues.join(', ')
3434
}
3535

36+
const mapHeaderValues = (header: string, callback: (value: string) => string): string => {
37+
const headerValues = getHeaderValueArray(header)
38+
const mappedValues = headerValues.map(callback)
39+
return mappedValues.join(', ')
40+
}
41+
3642
/**
3743
* Ensure the Netlify CDN varies on things that Next.js varies on,
3844
* e.g. i18n, preview mode, etc.
@@ -75,12 +81,16 @@ export const setCacheControlHeaders = (headers: Headers) => {
7581
!headers.has('cdn-cache-control') &&
7682
!headers.has('netlify-cdn-cache-control')
7783
) {
78-
const clientCacheControl = removeHeaderValues(cacheControl, [
84+
const privateCacheControl = omitHeaderValues(cacheControl, [
7985
's-maxage',
8086
'stale-while-revalidate',
8187
])
82-
headers.set('cache-control', clientCacheControl || 'public, max-age=0, must-revalidate')
83-
headers.set('netlify-cdn-cache-control', cacheControl)
88+
const sharedCacheControl = mapHeaderValues(cacheControl, (value) =>
89+
value === 'stale-while-revalidate' ? 'stale-while-revalidate=31536000' : value,
90+
)
91+
92+
headers.set('cache-control', privateCacheControl || 'public, max-age=0, must-revalidate')
93+
headers.set('netlify-cdn-cache-control', sharedCacheControl)
8494
}
8595
}
8696

‎tests/integration/cache-handler.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ describe('page router', () => {
4949
expect(call1.headers, 'a cache hit on the first invocation of a prerendered page').toEqual(
5050
expect.objectContaining({
5151
'x-nextjs-cache': 'HIT',
52-
'netlify-cdn-cache-control': 's-maxage=5, stale-while-revalidate',
52+
'netlify-cdn-cache-control': 's-maxage=5, stale-while-revalidate=31536000',
5353
}),
5454
)
5555

@@ -110,7 +110,7 @@ describe('app router', () => {
110110
expect(post1.headers, 'a cache hit on the first invocation of a prerendered page').toEqual(
111111
expect.objectContaining({
112112
'x-nextjs-cache': 'HIT',
113-
'netlify-cdn-cache-control': 's-maxage=5, stale-while-revalidate',
113+
'netlify-cdn-cache-control': 's-maxage=5, stale-while-revalidate=31536000',
114114
}),
115115
)
116116

‎tests/integration/revalidate-path.test.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@ test<FixtureTestContext>('should revalidate a route by path', async (ctx) => {
4545
expect(post1.headers, 'a cache hit on the first invocation of a prerendered page').toEqual(
4646
expect.objectContaining({
4747
'x-nextjs-cache': 'HIT',
48-
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate',
48+
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000',
4949
}),
5050
)
5151
expect(post1Route2.headers, 'a cache hit on the first invocation of a prerendered page').toEqual(
5252
expect.objectContaining({
5353
'x-nextjs-cache': 'HIT',
54-
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate',
54+
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000',
5555
}),
5656
)
5757

@@ -76,13 +76,13 @@ test<FixtureTestContext>('should revalidate a route by path', async (ctx) => {
7676
expect(post2.headers, 'a cache miss on the on demand revalidated path /1').toEqual(
7777
expect.objectContaining({
7878
'x-nextjs-cache': 'MISS',
79-
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate',
79+
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000',
8080
}),
8181
)
8282
expect(post2Route2.headers, 'a cache miss on the on demand revalidated path /2').toEqual(
8383
expect.objectContaining({
8484
'x-nextjs-cache': 'MISS',
85-
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate',
85+
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000',
8686
}),
8787
)
8888
expect(post2Date).not.toBe(post1Date)

‎tests/integration/revalidate-tags.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ test<FixtureTestContext>('should revalidate a route by tag', async (ctx) => {
4040
expect(post1.headers, 'a cache hit on the first invocation of a prerendered page').toEqual(
4141
expect.objectContaining({
4242
'x-nextjs-cache': 'HIT',
43-
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate',
43+
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000',
4444
}),
4545
)
4646

@@ -58,7 +58,7 @@ test<FixtureTestContext>('should revalidate a route by tag', async (ctx) => {
5858
expect(post2.headers, 'a cache miss on the on demand revalidated page').toEqual(
5959
expect.objectContaining({
6060
'x-nextjs-cache': 'MISS',
61-
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate',
61+
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000',
6262
}),
6363
)
6464
expect(post2Date).not.toBe(post1Date)
@@ -73,7 +73,7 @@ test<FixtureTestContext>('should revalidate a route by tag', async (ctx) => {
7373
expect(post3.headers, 'a cache hit on the revalidated and regenerated page').toEqual(
7474
expect.objectContaining({
7575
'x-nextjs-cache': 'HIT',
76-
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate',
76+
'netlify-cdn-cache-control': 's-maxage=31536000, stale-while-revalidate=31536000',
7777
}),
7878
)
7979
expect(post3Date).toBe(post2Date)

‎tests/integration/simple-app.test.ts

+7
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,10 @@ test<FixtureTestContext>('index should be normalized within the cacheHandler and
7070
expect(index.statusCode).toBe(200)
7171
expect(index.headers?.['cache-tag']).toBe('_N_T_/layout,_N_T_/page,_N_T_/')
7272
})
73+
74+
test<FixtureTestContext>('stale-while-revalidate headers should be normalized to include delta-seconds', async (ctx) => {
75+
await createFixture('simple-next-app', ctx)
76+
await runPlugin(ctx)
77+
const index = await invokeFunction(ctx, { url: '/' })
78+
expect(index.headers?.['netlify-cdn-cache-control']).toContain('stale-while-revalidate=31536000')
79+
})

0 commit comments

Comments
 (0)
Please sign in to comment.