Skip to content

Commit d315ee1

Browse files
authored
Ensure On-Demand revalidate does not consider preview cookie (#39313)
1 parent 6b49d47 commit d315ee1

File tree

4 files changed

+103
-0
lines changed

4 files changed

+103
-0
lines changed

packages/next/server/api-utils/node.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { IncomingMessage, ServerResponse } from 'http'
22
import type { NextApiRequest, NextApiResponse } from '../../shared/lib/utils'
33
import type { PageConfig } from 'next/types'
44
import {
5+
checkIsManualRevalidate,
56
PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER,
67
__ApiPreviewProps,
78
} from '.'
@@ -41,6 +42,12 @@ export function tryGetPreviewData(
4142
res: ServerResponse | BaseNextResponse,
4243
options: __ApiPreviewProps
4344
): PreviewData {
45+
// if an On-Demand revalidation is being done preview mode
46+
// is disabled
47+
if (options && checkIsManualRevalidate(req, options).isManualRevalidate) {
48+
return false
49+
}
50+
4451
// Read cached preview data if present
4552
if (SYMBOL_PREVIEW_DATA in req) {
4653
return (req as any)[SYMBOL_PREVIEW_DATA] as any

test/e2e/prerender.test.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import fs from 'fs-extra'
2+
import cookie from 'cookie'
23
import cheerio from 'cheerio'
34
import { join, sep } from 'path'
45
import escapeRegex from 'escape-string-regexp'
@@ -178,6 +179,11 @@ describe('Prerender', () => {
178179
initialRevalidateSeconds: 1,
179180
srcRoute: null,
180181
},
182+
'/preview': {
183+
dataRoute: `/_next/data/${next.buildId}/preview.json`,
184+
initialRevalidateSeconds: false,
185+
srcRoute: null,
186+
},
181187
'/api-docs/first': {
182188
dataRoute: `/_next/data/${next.buildId}/api-docs/first.json`,
183189
initialRevalidateSeconds: false,
@@ -1518,6 +1524,14 @@ describe('Prerender', () => {
15181524
p: 'p',
15191525
},
15201526
},
1527+
{
1528+
dataRouteRegex: normalizeRegEx(
1529+
`^\\/_next\\/data\\/${escapeRegex(
1530+
next.buildId
1531+
)}\\/preview.json$`
1532+
),
1533+
page: '/preview',
1534+
},
15211535
{
15221536
dataRouteRegex: normalizeRegEx(
15231537
`^\\/_next\\/data\\/${escapeRegex(
@@ -1772,6 +1786,67 @@ describe('Prerender', () => {
17721786
})
17731787
}
17741788

1789+
it('should revalidate manual revalidate with preview cookie', async () => {
1790+
const initialRes = await fetchViaHTTP(next.url, '/preview')
1791+
expect(initialRes.status).toBe(200)
1792+
1793+
const initial$ = cheerio.load(await initialRes.text())
1794+
const initialProps = JSON.parse(initial$('#props').text())
1795+
1796+
expect(initialProps).toEqual({
1797+
preview: false,
1798+
previewData: null,
1799+
})
1800+
1801+
const previewRes = await fetchViaHTTP(next.url, '/api/enable')
1802+
let previewCookie = ''
1803+
1804+
expect(previewRes.headers.get('set-cookie')).toMatch(
1805+
/(__prerender_bypass|__next_preview_data)/
1806+
)
1807+
1808+
previewRes.headers
1809+
.get('set-cookie')
1810+
.split(',')
1811+
.forEach((c) => {
1812+
c = cookie.parse(c)
1813+
const isBypass = c.__prerender_bypass
1814+
1815+
if (isBypass || c.__next_preview_data) {
1816+
if (previewCookie) previewCookie += '; '
1817+
1818+
previewCookie += `${
1819+
isBypass ? '__prerender_bypass' : '__next_preview_data'
1820+
}=${c[isBypass ? '__prerender_bypass' : '__next_preview_data']}`
1821+
}
1822+
})
1823+
1824+
const apiRes = await fetchViaHTTP(
1825+
next.url,
1826+
'/api/manual-revalidate',
1827+
{ pathname: '/preview' },
1828+
{
1829+
headers: {
1830+
cookie: previewCookie,
1831+
},
1832+
}
1833+
)
1834+
1835+
expect(apiRes.status).toBe(200)
1836+
expect(await apiRes.json()).toEqual({ revalidated: true })
1837+
1838+
const postRevalidateRes = await fetchViaHTTP(next.url, '/preview')
1839+
expect(initialRes.status).toBe(200)
1840+
1841+
const postRevalidate$ = cheerio.load(await postRevalidateRes.text())
1842+
const postRevalidateProps = JSON.parse(postRevalidate$('#props').text())
1843+
1844+
expect(postRevalidateProps).toEqual({
1845+
preview: false,
1846+
previewData: null,
1847+
})
1848+
})
1849+
17751850
it('should handle revalidating HTML correctly', async () => {
17761851
const route = '/blog/post-2/comment-2'
17771852
const initialHtml = await renderViaHTTP(next.url, route)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export default function handler(req, res) {
2+
res.setPreviewData({ hello: 'world' })
3+
res.json({ enabled: true })
4+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export function getStaticProps({ preview, previewData }) {
2+
return {
3+
props: {
4+
preview: preview || false,
5+
previewData: previewData || null,
6+
},
7+
}
8+
}
9+
10+
export default function Page(props) {
11+
return (
12+
<>
13+
<p id="page">/preview</p>
14+
<p id="props">{JSON.stringify(props)}</p>
15+
</>
16+
)
17+
}

0 commit comments

Comments
 (0)