Skip to content

Commit 3eff999

Browse files
authored
[next]: attach segment fallbacks when client param parsing is enabled (#14689)
Next.js builds segment prefetch files at build time, but the builder only attached fallbacks when allowQuery was empty. This meant segment prefetches for parametrized routes hit the function even though usable segment fallbacks existed. This change allows attaching segment fallbacks when client param parsing is enabled (which is always true when cache components is on), aligning Vercel behavior with next start. Cache keys still vary by `allowQuery`, so param isolation is preserved.
1 parent ee44634 commit 3eff999

File tree

5 files changed

+44
-10
lines changed

5 files changed

+44
-10
lines changed

.changeset/smooth-balloons-pay.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@vercel/next': patch
3+
---
4+
5+
attach segment fallbacks when client param parsing is enabled

packages/next/src/utils.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3285,13 +3285,15 @@ export const onPrerenderRoute =
32853285
) + prefetchSegmentSuffix;
32863286

32873287
// Only use the fallback value when the allowQuery is defined and
3288-
// is empty, which means that the segments do not vary based on
3289-
// the route parameters. This is safer than ensuring that we only
3290-
// use the fallback when this is not a fallback because we know in
3291-
// this new logic that it doesn't vary based on the route
3292-
// parameters and therefore can be used for all requests instead.
3288+
// either: (1) it is empty, meaning segments do not vary by params,
3289+
// or (2) client param parsing is enabled, meaning the segment
3290+
// payloads are safe to reuse across params.
32933291
let fallback: FileFsRef | null = null;
3294-
if (segmentAllowQuery && segmentAllowQuery.length === 0) {
3292+
const shouldAttachSegmentFallback =
3293+
segmentAllowQuery &&
3294+
(segmentAllowQuery.length === 0 ||
3295+
isAppClientParamParsingEnabled);
3296+
if (shouldAttachSegmentFallback) {
32953297
const fsPath = path.join(
32963298
segmentsDir,
32973299
segmentPath + prefetchSegmentSuffix

packages/next/test/integration/integration-2.test.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,27 @@ describe('PPR', () => {
598598
// cache posioning.
599599
expect(output['[lang]'].fallback).toEqual(null);
600600
});
601+
602+
it('should attach segment fallbacks when client param parsing is enabled', async () => {
603+
const {
604+
buildResult: { output },
605+
} = await runBuildLambda(path.join(__dirname, 'ppr-root-params'));
606+
607+
const segmentKeys = Object.keys(output).filter(
608+
key =>
609+
key.includes('[lang]/skills/[skill].segments/') &&
610+
key.endsWith('.segment.rsc')
611+
);
612+
613+
expect(segmentKeys.length).toBeGreaterThan(0);
614+
615+
for (const key of segmentKeys) {
616+
expect(output[key].type).toBe('Prerender');
617+
expect(output[key].fallback).toBeDefined();
618+
expect(output[key].fallback).not.toBeNull();
619+
expect(output[key].fallback.fsPath).toBeDefined();
620+
}
621+
});
601622
});
602623
});
603624

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export default async function Page({ params }) {
2+
const { lang, skill } = await params;
3+
4+
return (
5+
<div>
6+
Skill {skill} in {lang}
7+
</div>
8+
);
9+
}
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
11
module.exports = {
2-
experimental: {
3-
cacheComponents: true,
4-
dynamicIO: true,
5-
},
2+
cacheComponents: true,
63
};

0 commit comments

Comments
 (0)