-
Notifications
You must be signed in to change notification settings - Fork 27.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix top down generateStaticParams
in page
component
#55912
base: canary
Are you sure you want to change the base?
Fix top down generateStaticParams
in page
component
#55912
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Orca Security Scan Summary
Status | Check | Issues by priority | |
---|---|---|---|
![]() |
Secrets | ![]() ![]() ![]() ![]() |
View in Orca |
const fileTypesToResolve: (FileTypeValues | 'page')[] = | ||
Object.values(FILE_TYPES) | ||
|
||
// Special case for exports in parent pages |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This just fixes a special case (only for dynamic routes). Might be better to do a more extensive code rewrite on how pages in parent routes are added to the tree code for other exports in parent routes to work (if there are any such cases).
…page exist on parent route
let { generateStaticParams } = mod || {} | ||
const { getStaticPaths } = mod || {} | ||
|
||
// Look for generateStaticParams in template or page if not already found |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently it prioritizes exports in layout, then template and lastly page. Except for if the route does not contain a layout, then it prioritizes page. Once it has found generateStaticParams on a certain route level, it ignores all other exports for that level.
A better solution would be to check if generateStaticParams is exported from multiple files in the same route, and then throw an error. However this requires all these files in the route to be imported (layout, template, page) making for slower build times. Is it worth the trade-off to get good error messages?
Allow CI Workflow Run
Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer |
Allow CI Workflow Run
Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer |
@timneutkens @ijjk @shuding @huozhi @ztanner @feedthejim @wyattjoh It would be great to get some feedback on this PR, we are a few that reacted on the original issue (#53717) by now. Even though there is a pretty easy workaround, I think it would be great to get this issue fixed in some way to avoid confusion by users. Of course don't hesitate to tell me if you want this fix implemented in some other way. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this fix! I've left some initial comments
if (isDynamicSegment && !generateStaticParams) { | ||
;({ generateStaticParams } = (await segment[2]?.template?.[0]?.()) || {}) | ||
|
||
if (!generateStaticParams && isLayout) | ||
({ generateStaticParams } = (await segment[2]?.page?.[0]?.()) || {}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we're already checking for generateStaticParams
in the lines above I think we could probably simplify this to something like:
if (isDynamicSegment && !generateStaticParams) { | |
;({ generateStaticParams } = (await segment[2]?.template?.[0]?.()) || {}) | |
if (!generateStaticParams && isLayout) | |
({ generateStaticParams } = (await segment[2]?.page?.[0]?.()) || {}) | |
} | |
if (isDynamicSegment && !generateStaticParams) { | |
if (isLayout) { | |
;({ generateStaticParams } = (await segment[2]?.page?.[0]?.()) || {}) | |
} else { | |
;({ generateStaticParams } = (await segment[2]?.template?.[0]?.()) || {}) | |
} | |
} |
Object.values(FILE_TYPES) | ||
|
||
// Special case for exports in parent pages | ||
const isSegmentDynamic = /^\[.*\]$/.test(normalizedParallelSegments[0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be best to use our isDynamicRoute
util for this check
;({ generateStaticParams } = (await segment[2]?.template?.[0]?.()) || {}) | ||
|
||
if (!generateStaticParams && isLayout) | ||
({ generateStaticParams } = (await segment[2]?.page?.[0]?.()) || {}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unrelated to your changes, but can we use the LoaderTree
type for the segment
argument in this function? That way we can get some typesafety here
// Special case for exports in parent pages | ||
const isSegmentDynamic = /^\[.*\]$/.test(normalizedParallelSegments[0]) | ||
const isFinalSegment = | ||
normalizedParallelSegments[0] === page.split('/').at(-2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to remind myself why this would be -2
which was a bit confusing. Perhaps we can first run page through normalizeAppPath
-- that'll give us something like /gen-params-top-down-page/[lang]/[slug]
. Then we can simplify this check to be normalizedParallelSegments[0] === normalizedAppPath.at(-1)
@@ -302,9 +304,18 @@ async function createTreeCodeFromPath( | |||
|
|||
const parallelSegmentPath = subSegmentPath.join('/') | |||
|
|||
const fileTypesToResolve: (FileTypeValues | 'page')[] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since we're creating a separate type for this, I think it'd make more sense to add the | 'page'
to FileTypeValues
rather than inlining it
Failing test suitesCommit: a268c4e
Expand output● app dir - hooks › useSelectedLayoutSegments › should return an empty array in pages
● app dir - hooks › useSelectedLayoutSegment › should return null in pages
Read more about building and testing Next.js in contributing.md.
Expand output● middleware - development errors › when there is a compilation error from boot › logs the error correctly
Read more about building and testing Next.js in contributing.md.
Expand output● use-params › should work for nested dynamic params
● use-params › should work for nested dynamic params client navigating
Read more about building and testing Next.js in contributing.md. |
Stats from current PRDefault BuildGeneral Overall increase
|
vercel/next.js canary | viktorronnback/next.js generate-static-params-page | Change | |
---|---|---|---|
buildDuration | 10.5s | 10.3s | N/A |
buildDurationCached | 5.8s | 6.6s | |
nodeModulesSize | 199 MB | 199 MB | |
nextStartRea..uration (ms) | 420ms | 424ms | N/A |
Client Bundles (main, webpack)
vercel/next.js canary | viktorronnback/next.js generate-static-params-page | Change | |
---|---|---|---|
199-HASH.js gzip | 30.6 kB | 30.6 kB | N/A |
3f784ff6-HASH.js gzip | 53.3 kB | 53.3 kB | ✓ |
494.HASH.js gzip | 180 B | 181 B | N/A |
framework-HASH.js gzip | 45.2 kB | 45.2 kB | ✓ |
main-app-HASH.js gzip | 241 B | 239 B | N/A |
main-HASH.js gzip | 31.7 kB | 31.7 kB | N/A |
webpack-HASH.js gzip | 1.7 kB | 1.7 kB | ✓ |
Overall change | 100 kB | 100 kB | ✓ |
Legacy Client Bundles (polyfills)
vercel/next.js canary | viktorronnback/next.js generate-static-params-page | Change | |
---|---|---|---|
polyfills-HASH.js gzip | 31 kB | 31 kB | ✓ |
Overall change | 31 kB | 31 kB | ✓ |
Client Pages
vercel/next.js canary | viktorronnback/next.js generate-static-params-page | Change | |
---|---|---|---|
_app-HASH.js gzip | 194 B | 195 B | N/A |
_error-HASH.js gzip | 182 B | 181 B | N/A |
amp-HASH.js gzip | 501 B | 503 B | N/A |
css-HASH.js gzip | 322 B | 323 B | N/A |
dynamic-HASH.js gzip | 2.5 kB | 2.5 kB | ✓ |
edge-ssr-HASH.js gzip | 253 B | 255 B | N/A |
head-HASH.js gzip | 348 B | 347 B | N/A |
hooks-HASH.js gzip | 369 B | 368 B | N/A |
image-HASH.js gzip | 4.27 kB | 4.27 kB | N/A |
index-HASH.js gzip | 256 B | 256 B | ✓ |
link-HASH.js gzip | 2.61 kB | 2.6 kB | N/A |
routerDirect..HASH.js gzip | 311 B | 311 B | ✓ |
script-HASH.js gzip | 384 B | 383 B | N/A |
withRouter-HASH.js gzip | 307 B | 308 B | N/A |
1afbb74e6ecf..834.css gzip | 106 B | 106 B | ✓ |
Overall change | 3.17 kB | 3.17 kB | ✓ |
Client Build Manifests
vercel/next.js canary | viktorronnback/next.js generate-static-params-page | Change | |
---|---|---|---|
_buildManifest.js gzip | 484 B | 483 B | N/A |
Overall change | 0 B | 0 B | ✓ |
Rendered Page Sizes
vercel/next.js canary | viktorronnback/next.js generate-static-params-page | Change | |
---|---|---|---|
index.html gzip | 528 B | 527 B | N/A |
link.html gzip | 538 B | 540 B | N/A |
withRouter.html gzip | 524 B | 522 B | N/A |
Overall change | 0 B | 0 B | ✓ |
Edge SSR bundle Size
vercel/next.js canary | viktorronnback/next.js generate-static-params-page | Change | |
---|---|---|---|
edge-ssr.js gzip | 92.6 kB | 92.7 kB | N/A |
page.js gzip | 145 kB | 145 kB | N/A |
Overall change | 0 B | 0 B | ✓ |
Middleware size
vercel/next.js canary | viktorronnback/next.js generate-static-params-page | Change | |
---|---|---|---|
middleware-b..fest.js gzip | 626 B | 626 B | ✓ |
middleware-r..fest.js gzip | 150 B | 151 B | N/A |
middleware.js gzip | 35.7 kB | 35.7 kB | N/A |
edge-runtime..pack.js gzip | 1.92 kB | 1.92 kB | ✓ |
Overall change | 2.55 kB | 2.55 kB | ✓ |
Next Runtimes
vercel/next.js canary | viktorronnback/next.js generate-static-params-page | Change | |
---|---|---|---|
app-page-exp...dev.js gzip | 168 kB | 168 kB | ✓ |
app-page-exp..prod.js gzip | 93.8 kB | 93.8 kB | ✓ |
app-page-tur..prod.js gzip | 94.5 kB | 94.5 kB | ✓ |
app-page-tur..prod.js gzip | 89.1 kB | 89.1 kB | ✓ |
app-page.run...dev.js gzip | 138 kB | 138 kB | ✓ |
app-page.run..prod.js gzip | 88.4 kB | 88.4 kB | ✓ |
app-route-ex...dev.js gzip | 24.2 kB | 24.2 kB | ✓ |
app-route-ex..prod.js gzip | 16.8 kB | 16.8 kB | ✓ |
app-route-tu..prod.js gzip | 16.9 kB | 16.9 kB | ✓ |
app-route-tu..prod.js gzip | 16.4 kB | 16.4 kB | ✓ |
app-route.ru...dev.js gzip | 23.6 kB | 23.6 kB | ✓ |
app-route.ru..prod.js gzip | 16.4 kB | 16.4 kB | ✓ |
pages-api-tu..prod.js gzip | 9.37 kB | 9.37 kB | ✓ |
pages-api.ru...dev.js gzip | 9.64 kB | 9.64 kB | ✓ |
pages-api.ru..prod.js gzip | 9.37 kB | 9.37 kB | ✓ |
pages-turbo...prod.js gzip | 21.9 kB | 21.9 kB | ✓ |
pages.runtim...dev.js gzip | 22.6 kB | 22.6 kB | ✓ |
pages.runtim..prod.js gzip | 21.9 kB | 21.9 kB | ✓ |
server.runti..prod.js gzip | 49.3 kB | 49.3 kB | ✓ |
Overall change | 930 kB | 930 kB | ✓ |
What?
Fixes #53717 and #55574.
Why?
Exporting
generateStaticParams
from nested dynamic routes only works if "parent" routes exports from thelayout
component.How?
Added
page
component of "parent" routes (only dynamic routes) to tree code in loader.