Skip to content
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: expected "catch all routes" are not matched in “parallel routes" #58368

Merged
merged 10 commits into from
Nov 13, 2023
12 changes: 10 additions & 2 deletions packages/next/src/build/normalize-catchall-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,21 @@ export function normalizeCatchAllRoutes(
normalizer = new AppPathnameNormalizer()
) {
const catchAllRoutes = [
...new Set(Object.values(appPaths).flat().filter(isCatchAllRoute)),
...new Set(
Object.values(appPaths)
.flat()
.filter(isCatchAllRoute)
// Sorting is important because we want to match the most specific path.
.sort((a, b) => b.split('/').length - a.split('/').length)
),
]

for (const appPath of Object.keys(appPaths)) {
for (const catchAllRoute of catchAllRoutes) {
const normalizedCatchAllRoute = normalizer.normalize(catchAllRoute)
const normalizedCatchAllRouteBasePath = normalizedCatchAllRoute.slice(
0,
normalizedCatchAllRoute.indexOf('[')
normalizedCatchAllRoute.search(catchAllRouteRegex)
)

if (
Expand Down Expand Up @@ -48,6 +54,8 @@ function hasMatchedSlots(path1: string, path2: string): boolean {
return true
}

const catchAllRouteRegex = /\[?\[\.\.\./

function isCatchAllRoute(pathname: string): boolean {
return pathname.includes('[...') || pathname.includes('[[...')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return 'slot catchall'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Default() {
return (
<div>
<div>Default</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Foo() {
return 'foo id catchAll'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Foo() {
return 'foo slot'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return 'main catchall'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Bar() {
return 'bar'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return 'foo id'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return 'foo'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Link from 'next/link'

export default function Layout({ children, slot }) {
return (
<div>
<div>Main content</div>
<div id="main">{children}</div>
<div>
Slot content:
<div id="slot-content">{slot}</div>
</div>

<div>
<Link href="/parallel-nested-catchall/foo">foo</Link>
</div>
<div>
<Link href="/parallel-nested-catchall/bar">catchall bar</Link>
</div>
<div>
<Link href="/parallel-nested-catchall/foo/123">catchall foo id</Link>
</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Page() {
return (
<div>
<div>Page</div>
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,37 @@ createNextDescribe(
)
})

it('Should match the catch-all routes of the more specific path, If there is more than one catch-all route', async () => {
const browser = await next.browser('/parallel-nested-catchall')

await browser
.elementByCss('[href="/parallel-nested-catchall/foo"]')
.click()
await check(() => browser.waitForElementByCss('#main').text(), 'foo')
await check(
() => browser.waitForElementByCss('#slot-content').text(),
'foo slot'
)

await browser
.elementByCss('[href="/parallel-nested-catchall/bar"]')
.click()
await check(() => browser.waitForElementByCss('#main').text(), 'bar')
await check(
() => browser.waitForElementByCss('#slot-content').text(),
'slot catchall'
)

await browser
.elementByCss('[href="/parallel-nested-catchall/foo/123"]')
.click()
await check(() => browser.waitForElementByCss('#main').text(), 'foo id')
await check(
() => browser.waitForElementByCss('#slot-content').text(),
'foo id catchAll'
)
})

it('should navigate with a link with prefetch=false', async () => {
const browser = await next.browser('/parallel-prefetch-false')

Expand Down
Loading