Skip to content

Commit 43b64cc

Browse files
authored
Ignore pending revalidations during prerendering (vercel#81621)
When reading a cache entry, we usually check its tags against the recently revalidated tags, and dismiss it, if it has any of those tags. However, this is only needed during dynamic requests, specifically during the rendering that follows a revalidating server action. During the prerender validation in dev mode, we should not discard the cache entries based on the pending revalidation. The concurrently running dynamic rendering will handle discarding and recreating those cache entries. During build-time prerendering, there will never be any pending revalidated tags. This fixes a bug where a different value was rendered when revalidating with a server action and then reloading the page afterwards (or triggering another unrelated revalidating server action).
1 parent 7efeae3 commit 43b64cc

File tree

2 files changed

+33
-12
lines changed

2 files changed

+33
-12
lines changed

packages/next/src/server/use-cache/use-cache-wrapper.ts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,7 @@ export function cache(
10041004
shouldDiscardCacheEntry(
10051005
entry,
10061006
workStore,
1007+
workUnitStore,
10071008
implicitTags,
10081009
implicitTagsExpiration
10091010
)
@@ -1284,17 +1285,12 @@ function shouldForceRevalidate(
12841285
function shouldDiscardCacheEntry(
12851286
entry: CacheEntry,
12861287
workStore: WorkStore,
1288+
workUnitStore: WorkUnitStore | undefined,
12871289
implicitTags: string[],
12881290
implicitTagsExpiration: number
12891291
): boolean {
1290-
// If the cache entry contains revalidated tags that the cache handler might
1291-
// not know about yet, we need to discard it.
1292-
if (entry.tags.some((tag) => isRecentlyRevalidatedTag(tag, workStore))) {
1293-
return true
1294-
}
1295-
12961292
// If the cache entry was created before any of the implicit tags were
1297-
// revalidated last, we also need to discard it.
1293+
// revalidated last, we need to discard it.
12981294
if (entry.timestamp <= implicitTagsExpiration) {
12991295
debug?.(
13001296
'entry was created at',
@@ -1306,6 +1302,33 @@ function shouldDiscardCacheEntry(
13061302
return true
13071303
}
13081304

1305+
// During prerendering, we ignore recently revalidated tags. In dev mode, we
1306+
// can assume that the dynamic dev rendering will have discarded and recreated
1307+
// the affected cache entries, and we don't want to discard those again during
1308+
// the prerender validation. During build-time prerendering, there will never
1309+
// be any pending revalidated tags.
1310+
if (workUnitStore) {
1311+
switch (workUnitStore.type) {
1312+
case 'prerender':
1313+
return false
1314+
case 'prerender-client':
1315+
case 'prerender-ppr':
1316+
case 'prerender-legacy':
1317+
case 'request':
1318+
case 'cache':
1319+
case 'unstable-cache':
1320+
break
1321+
default:
1322+
workUnitStore satisfies never
1323+
}
1324+
}
1325+
1326+
// If the cache entry contains revalidated tags that the cache handler might
1327+
// not know about yet, we need to discard it.
1328+
if (entry.tags.some((tag) => isRecentlyRevalidatedTag(tag, workStore))) {
1329+
return true
1330+
}
1331+
13091332
// Finally, if any of the implicit tags have been revalidated recently, we
13101333
// also need to discard the cache entry.
13111334
if (implicitTags.some((tag) => isRecentlyRevalidatedTag(tag, workStore))) {
@@ -1326,8 +1349,9 @@ function isRecentlyRevalidatedTag(tag: string, workStore: WorkStore): boolean {
13261349
}
13271350

13281351
// It could also have been revalidated by the currently running server action.
1329-
// In this case the revalidation might not have been propagated to the cache
1330-
// handler yet, so we read it from the pending tags in the work store.
1352+
// In this case the revalidation might not have been fully propagated by a
1353+
// remote cache handler yet, so we read it from the pending tags in the work
1354+
// store.
13311355
if (pendingRevalidatedTags?.includes(tag)) {
13321356
debug?.('tag', tag, 'was just revalidated')
13331357

test/cache-components-tests-manifest.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@
2727
"searchparams-reuse-loading should re-use loading from \"full\" prefetch for param-less URL when navigating to param-full route"
2828
]
2929
},
30-
"test/e2e/app-dir/use-cache/use-cache.test.ts": {
31-
"failed": ["use-cache should update after unstable_expireTag correctly"]
32-
},
3330
"test/production/app-dir/browser-chunks/browser-chunks.test.ts": {
3431
"failed": [
3532
"browser-chunks must not bundle any server modules into browser chunks"

0 commit comments

Comments
 (0)