forked from vercel/next.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix catch-all route normalization for default parallel routes (vercel…
…#60240) ### What? When relying on a `default` route as a fallback, greedier catch-all segments in the application hierarchy would take precedence, causing unexpected errors/matching behavior. ### Why? When performing parallel route catch-all normalization, we push potential catch-all matches to paths without considering that a path might instead be matched by a `default` page. Because of this, the catch-all take precedence and the app will not try and load the default. For example, given this structure: ``` { "/": ["/page"], "/[[...catchAll]]": ["/[[...catchAll]]/page"], "/nested/[foo]/[bar]": ["/nested/[foo]/[bar]/@slot/page"], "/nested/[foo]/[bar]/[baz]": ["/nested/[foo]/[bar]/@slot/[baz]/page"], } ``` (Where there's a `/nested/[foo]/[bar]/default.tsx`) The route normalization logic would produce: ``` { "/": ["/page"], "/[[...catchAll]]": ["/[[...catchAll]]/page"], "/nested/[foo]/[bar]": [ "/nested/[foo]/[bar]/@slot/page", "/[[...catchAll]]/page", ], "/nested/[foo]/[bar]/[baz]": [ "/nested/[foo]/[bar]/@slot/[baz]/page", "/[[...catchAll]]/page", ], } ``` This means that when building the `LoaderTree`, it won't ever try to find the default for that segment. **This solution operates under the assumption that if you defined a `default` at a particular layout segment, you intend for that to render in place of a greedier catch-all.** (Let me know if this is an incorrect assumption) ### How? We can't safely normalize catch-all parallel routes without having context about where the `default` segments are, so this updates `appPaths` to be inclusive of default segments and then filters them when doing anything relating to build/export to maintain existing behavior. We use this information to check if an existing default exists at the same segment level that we'd push the catch-all to. If one exists, we don't push the catch-all. Otherwise we proceed as normal. Closes NEXT-1987
- Loading branch information
Showing
19 changed files
with
140 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export function isDefaultRoute(value?: string) { | ||
return value?.endsWith('/default') | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
test/e2e/app-dir/parallel-routes-catchall-default/app/[locale]/[[...catchAll]]/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function Page() { | ||
return <div>/[locale]/[[...catchAll]]/page.tsx</div> | ||
} |
3 changes: 3 additions & 0 deletions
3
.../parallel-routes-catchall-default/app/[locale]/nested/[foo]/[bar]/@slot/[baz]/default.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function Page() { | ||
return <div>/[locale]/nested/[foo]/[bar]/@slot/[baz]/default.tsx</div> | ||
} |
3 changes: 3 additions & 0 deletions
3
...dir/parallel-routes-catchall-default/app/[locale]/nested/[foo]/[bar]/@slot/[baz]/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function Page({ params }) { | ||
return <div>/[locale]/nested/[foo]/[bar]/@slot/[baz]/page.tsx</div> | ||
} |
3 changes: 3 additions & 0 deletions
3
...pp-dir/parallel-routes-catchall-default/app/[locale]/nested/[foo]/[bar]/@slot/default.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function Page() { | ||
return <div>/[locale]/nested/[foo]/[bar]/@slot/default.tsx</div> | ||
} |
3 changes: 3 additions & 0 deletions
3
...e/app-dir/parallel-routes-catchall-default/app/[locale]/nested/[foo]/[bar]/@slot/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function Foo() { | ||
return <div>/[locale]/nested/[foo]/[bar]/@slot/page.tsx</div> | ||
} |
3 changes: 3 additions & 0 deletions
3
.../e2e/app-dir/parallel-routes-catchall-default/app/[locale]/nested/[foo]/[bar]/default.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function Page() { | ||
return <div>/[locale]/nested/[foo]/[bar]/default.tsx</div> | ||
} |
8 changes: 8 additions & 0 deletions
8
test/e2e/app-dir/parallel-routes-catchall-default/app/[locale]/nested/[foo]/[bar]/layout.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
export default function Layout({ children, slot }) { | ||
return ( | ||
<> | ||
Children: <div id="nested-children">{children}</div> | ||
Slot: <div id="slot">{slot}</div> | ||
</> | ||
) | ||
} |
11 changes: 11 additions & 0 deletions
11
test/e2e/app-dir/parallel-routes-catchall-default/app/layout.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import React from 'react' | ||
|
||
export default function Root({ children }: { children: React.ReactNode }) { | ||
return ( | ||
<html> | ||
<body> | ||
Children: <div id="children">{children}</div> | ||
</body> | ||
</html> | ||
) | ||
} |
3 changes: 3 additions & 0 deletions
3
test/e2e/app-dir/parallel-routes-catchall-default/app/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default async function Home() { | ||
return <div>Root Page</div> | ||
} |
6 changes: 6 additions & 0 deletions
6
test/e2e/app-dir/parallel-routes-catchall-default/next.config.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/** | ||
* @type {import('next').NextConfig} | ||
*/ | ||
const nextConfig = {} | ||
|
||
module.exports = nextConfig |
44 changes: 44 additions & 0 deletions
44
test/e2e/app-dir/parallel-routes-catchall-default/parallel-routes-catchall-default.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { createNextDescribe } from 'e2e-utils' | ||
|
||
createNextDescribe( | ||
'parallel-routes-catchall-default', | ||
{ | ||
files: __dirname, | ||
}, | ||
({ next }) => { | ||
it('should match default paths before catch-all', async () => { | ||
let browser = await next.browser('/en/nested') | ||
|
||
// we have a top-level catch-all but the /nested dir doesn't have a default/page until the /[foo]/[bar] segment | ||
// so we expect the top-level catch-all to render | ||
expect(await browser.elementById('children').text()).toBe( | ||
'/[locale]/[[...catchAll]]/page.tsx' | ||
) | ||
|
||
browser = await next.browser('/en/nested/foo/bar') | ||
|
||
// we're now at the /[foo]/[bar] segment, so we expect the matched page to be the default (since there's no page defined) | ||
expect(await browser.elementById('nested-children').text()).toBe( | ||
'/[locale]/nested/[foo]/[bar]/default.tsx' | ||
) | ||
|
||
// we expect the slot to match since there's a page defined at this segment | ||
expect(await browser.elementById('slot').text()).toBe( | ||
'/[locale]/nested/[foo]/[bar]/@slot/page.tsx' | ||
) | ||
|
||
browser = await next.browser('/en/nested/foo/bar/baz') | ||
|
||
// the page slot should still be the one matched at the /[foo]/[bar] segment because it's the default and we | ||
// didn't define a page at the /[foo]/[bar]/[baz] segment | ||
expect(await browser.elementById('nested-children').text()).toBe( | ||
'/[locale]/nested/[foo]/[bar]/default.tsx' | ||
) | ||
|
||
// however we do have a slot for the `[baz]` segment and so we expect that to no match | ||
expect(await browser.elementById('slot').text()).toBe( | ||
'/[locale]/nested/[foo]/[bar]/@slot/[baz]/page.tsx' | ||
) | ||
}) | ||
} | ||
) |
7 changes: 0 additions & 7 deletions
7
test/e2e/app-dir/parallel-routes-catchall/app/@slot/default.tsx
This file was deleted.
Oops, something went wrong.