Skip to content

Commit

Permalink
fix: unstable_cache should not cache new result in draft mode (#67772)
Browse files Browse the repository at this point in the history
### What?
In draft mode, as of right now, `unstable_cache` does not read from the
static store, but still write to it. This leads to the following
scenario:

1. Content Editor enters draft mode to test his content
2. Content Editor skips cache and reads preview data
3. Preview data is written to store
4. Random user without draft mode receives preview data until cache is
revalidated again

### Why?
There's an early exit before reading from the cache - the new result is
written to the cache nonetheless though.

### How?
New result is only cached if draft mode is disabled.

Co-authored-by: JJ Kasper <jj@jjsweb.site>
  • Loading branch information
timfuhrmann and ijjk authored Jul 15, 2024
1 parent b7f9f1f commit 92ce2d6
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 9 deletions.
22 changes: 13 additions & 9 deletions packages/next/src/server/web/spec-extension/unstable-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,15 +267,19 @@ export function unstable_cache<T extends Callback>(
cb,
...args
)
cacheNewResult(
result,
incrementalCache,
cacheKey,
tags,
options.revalidate,
fetchIdx,
fetchUrl
)

if (!staticGenerationStore.isDraftMode) {
cacheNewResult(
result,
incrementalCache,
cacheKey,
tags,
options.revalidate,
fetchIdx,
fetchUrl
)
}

return result
} else {
noStoreFetchIdx += 1
Expand Down
20 changes: 20 additions & 0 deletions test/e2e/app-dir/app-static/app-static.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3489,6 +3489,26 @@ describe('app-dir static/dynamic handling', () => {
expect(data).not.toEqual(data2)
})

it('should not cache new result 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(';', 1)[0] }

expect(cookieHeader.Cookie).toBeTruthy()

const res = await next.fetch('/unstable-cache/dynamic', {
headers: cookieHeader,
})
const html = await res.text()
const data = cheerio.load(html)('#cached-data').text()

const res2 = await next.fetch('/unstable-cache/dynamic')
const html2 = await res2.text()
const data2 = cheerio.load(html2)('#cached-data').text()

expect(data).not.toEqual(data2)
})

it('should not error when retrieving the value undefined', async () => {
const res = await next.fetch('/unstable-cache/dynamic-undefined')
const html = await res.text()
Expand Down

0 comments on commit 92ce2d6

Please sign in to comment.