Skip to content

Commit

Permalink
fix: moved down segment path handling after cache headers are set (#7…
Browse files Browse the repository at this point in the history
…4893)

Previously, the segment path handling was returning before the
`x-nextjs-cache` headers were sent, this moves it below that to ensure
that the correct cache headers are added.
  • Loading branch information
wyattjoh authored Jan 15, 2025
1 parent c07e2c7 commit 641612e
Showing 1 changed file with 47 additions and 50 deletions.
97 changes: 47 additions & 50 deletions packages/next/src/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3062,56 +3062,6 @@ export default abstract class Server<
}
)

if (isRoutePPREnabled && typeof segmentPrefetchHeader === 'string') {
// This is a prefetch request issued by the client Segment Cache. These
// should never reach the application layer (lambda). We should either
// respond from the cache (HIT) or respond with 204 No Content (MISS).

// Set a header to indicate that PPR is enabled for this route. This
// lets the client distinguish between a regular cache miss and a cache
// miss due to PPR being disabled. In other contexts this header is used
// to indicate that the response contains dynamic data, but here we're
// only using it to indicate that the feature is enabled — the segment
// response itself contains whether the data is dynamic.
res.setHeader(NEXT_DID_POSTPONE_HEADER, '2')

if (
cacheEntry !== null &&
// This is always true at runtime but is needed to refine the type
// of cacheEntry.value to CachedAppPageValue, because the outer
// ResponseCacheEntry is not a discriminated union.
cacheEntry.value?.kind === CachedRouteKind.APP_PAGE &&
cacheEntry.value.segmentData
) {
const matchedSegment = cacheEntry.value.segmentData.get(
segmentPrefetchHeader
)
if (matchedSegment !== undefined) {
// Cache hit
return {
type: 'rsc',
body: RenderResult.fromStatic(matchedSegment),
// TODO: Eventually this should use revalidate time of the
// individual segment, not the whole page.
revalidate: cacheEntry.revalidate,
}
}
}

// Cache miss. Either a cache entry for this route has not been generated
// (which technically should not be possible when PPR is enabled, because
// at a minimum there should always be a fallback entry) or there's no
// match for the requested segment. Respond with a 204 No Content. We
// don't bother to respond with 404, because these requests are only
// issued as part of a prefetch.
res.statusCode = 204
return {
type: 'rsc',
body: RenderResult.fromStatic(''),
revalidate: cacheEntry?.revalidate,
}
}

if (isPreviewMode) {
res.setHeader(
'Cache-Control',
Expand Down Expand Up @@ -3204,6 +3154,53 @@ export default abstract class Server<

const { value: cachedData } = cacheEntry

if (isRoutePPREnabled && typeof segmentPrefetchHeader === 'string') {
// This is a prefetch request issued by the client Segment Cache. These
// should never reach the application layer (lambda). We should either
// respond from the cache (HIT) or respond with 204 No Content (MISS).

// Set a header to indicate that PPR is enabled for this route. This
// lets the client distinguish between a regular cache miss and a cache
// miss due to PPR being disabled. In other contexts this header is used
// to indicate that the response contains dynamic data, but here we're
// only using it to indicate that the feature is enabled — the segment
// response itself contains whether the data is dynamic.
res.setHeader(NEXT_DID_POSTPONE_HEADER, '2')

if (
// This is always true at runtime but is needed to refine the type
// of cacheEntry.value to CachedAppPageValue, because the outer
// ResponseCacheEntry is not a discriminated union.
cachedData?.kind === CachedRouteKind.APP_PAGE &&
cachedData.segmentData
) {
const matchedSegment = cachedData.segmentData.get(segmentPrefetchHeader)
if (matchedSegment !== undefined) {
// Cache hit
return {
type: 'rsc',
body: RenderResult.fromStatic(matchedSegment),
// TODO: Eventually this should use revalidate time of the
// individual segment, not the whole page.
revalidate: cacheEntry.revalidate,
}
}
}

// Cache miss. Either a cache entry for this route has not been generated
// (which technically should not be possible when PPR is enabled, because
// at a minimum there should always be a fallback entry) or there's no
// match for the requested segment. Respond with a 204 No Content. We
// don't bother to respond with 404, because these requests are only
// issued as part of a prefetch.
res.statusCode = 204
return {
type: 'rsc',
body: RenderResult.fromStatic(''),
revalidate: cacheEntry?.revalidate,
}
}

// If the cache value is an image, we should error early.
if (cachedData?.kind === CachedRouteKind.IMAGE) {
throw new Error('invariant SSG should not return an image cache value')
Expand Down

0 comments on commit 641612e

Please sign in to comment.