Update cache handling in draft mode (#51663)

Similar to `getStaticProps` when draft mode is enabled we should bypass
the cache so fresh data is shown.

x-ref: [slack
thread](https://vercel.slack.com/archives/C052BQ8F9EJ/p1687440125828479?thread_ts=1684336597.437409&cid=C052BQ8F9EJ)
and
[tweet](https://twitter.com/tomus_sherman/status/1669023879656873988)

---------

Co-authored-by: Steven <steven@ceriously.com>
This commit is contained in:
JJ Kasper 2023-06-22 14:03:11 -07:00 committed by GitHub
parent 82abde8dd9
commit f749684921
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 63 additions and 2 deletions

View file

@ -45,6 +45,8 @@ export interface StaticGenerationStore {
status: number
cacheStatus: 'hit' | 'miss'
}>
isDraftMode?: boolean
}
export type StaticGenerationAsyncStorage =

View file

@ -69,6 +69,8 @@ export const StaticGenerationAsyncStorageWrapper: AsyncStorageWrapper<
isPrerendering: renderOpts.nextExport,
fetchCache: renderOpts.fetchCache,
isOnDemandRevalidate: renderOpts.isOnDemandRevalidate,
isDraftMode: renderOpts.isDraftMode,
}
// TODO: remove this when we resolve accessing the store outside the execution context

View file

@ -126,7 +126,11 @@ export function patchFetch({
// If the staticGenerationStore is not available, we can't do any
// special treatment of fetch, therefore fallback to the original
// fetch implementation.
if (!staticGenerationStore || (init?.next as any)?.internal) {
if (
!staticGenerationStore ||
(init?.next as any)?.internal ||
staticGenerationStore.isDraftMode
) {
return originFetch(input, init)
}

View file

@ -465,6 +465,7 @@ createNextDescribe(
expect(files).toEqual([
'(new)/custom/page.js',
'api/draft-mode/route.js',
'api/revalidate-path-edge/route.js',
'api/revalidate-path-node/route.js',
'api/revalidate-tag-edge/route.js',
@ -1139,6 +1140,37 @@ createNextDescribe(
})
}
it('should skip cache in draft mode', async () => {
const draftRes = await next.fetch('/api/draft-mode?status=enable')
const setCookie = draftRes.headers.get('set-cookie')
const cookieHeader = { Cookie: setCookie?.split(';')[0] }
expect(cookieHeader.Cookie).toBeTruthy()
const res = await next.fetch('/ssg-draft-mode/test-1', {
headers: cookieHeader,
})
const html = await res.text()
const $ = cheerio.load(html)
const data1 = $('#data').text()
expect(data1).toBeTruthy()
expect(JSON.parse($('#draft-mode').text())).toEqual({ isEnabled: true })
const res2 = await next.fetch('/ssg-draft-mode/test-1', {
headers: cookieHeader,
})
const html2 = await res2.text()
const $2 = cheerio.load(html2)
const data2 = $2('#data').text()
expect(data2).toBeTruthy()
expect(data1).not.toBe(data2)
expect(JSON.parse($2('#draft-mode').text())).toEqual({ isEnabled: true })
})
it('should handle partial-gen-params with default dynamicParams correctly', async () => {
const res = await next.fetch('/partial-gen-params/en/first')
expect(res.status).toBe(200)

View file

@ -0,0 +1,16 @@
import { draftMode } from 'next/headers'
import { NextRequest, NextResponse } from 'next/server'
export function GET(req: NextRequest) {
const status = req.nextUrl.searchParams.get('status')
if (status === 'enable') {
draftMode().enable()
} else {
draftMode().disable()
}
return NextResponse.json({
status,
})
}

View file

@ -1,11 +1,16 @@
import { draftMode } from 'next/headers'
export default function Page() {
export default async function Page() {
const data = await fetch(
'https://next-data-api-endpoint.vercel.app/api/random'
).then((res) => res.text())
const { isEnabled } = draftMode()
return (
<main>
<pre id="draft-mode">{JSON.stringify({ isEnabled })}</pre>
<p id="data">{data}</p>
</main>
)
}