interception routes: fix interception for dynamic routes (#58198)

This PR fixes the bug in which interception routes of the form `(.)[param]` would not intercept navigations.

The bug happened because we would not create a dynamic route matcher for the intercepted route, so we would never match the correct dynamic route when hitting the server, falling back to the base one. 

The fix consists of fixing the logic that checks for a dynamic route so that it checks the correct path when handling an interception route.

There's probably a better fix here, advice welcome

fixes #52533
This commit is contained in:
Jimmy Lai 2023-11-08 19:57:57 +01:00 committed by GitHub
parent a6a8c8422c
commit 536d2dbc44
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 105 additions and 1 deletions

View file

@ -4,6 +4,10 @@ import { isDynamicRoute } from '../shared/lib/router/utils'
import { removeTrailingSlash } from '../shared/lib/router/utils/remove-trailing-slash'
import type { Redirect } from './load-custom-routes'
import { tryToParsePath } from './try-to-parse-path'
import {
extractInterceptionRouteInformation,
isInterceptionRouteAppPath,
} from '../server/future/helpers/interception-routes'
export function createClientRouterFilter(
paths: string[],
@ -16,8 +20,12 @@ export function createClientRouterFilter(
const staticPaths = new Set<string>()
const dynamicPaths = new Set<string>()
for (const path of paths) {
for (let path of paths) {
if (isDynamicRoute(path)) {
if (isInterceptionRouteAppPath(path)) {
path = extractInterceptionRouteInformation(path).interceptedRoute
}
let subPath = ''
const pathParts = path.split('/')

View file

@ -1,6 +1,15 @@
import {
extractInterceptionRouteInformation,
isInterceptionRouteAppPath,
} from '../../../../server/future/helpers/interception-routes'
// Identify /[param]/ in route string
const TEST_ROUTE = /\/\[[^/]+?\](?=\/|$)/
export function isDynamicRoute(route: string): boolean {
if (isInterceptionRouteAppPath(route)) {
route = extractInterceptionRouteInformation(route).interceptedRoute
}
return TEST_ROUTE.test(route)
}

View file

@ -0,0 +1,8 @@
export default function Page({ params: { id } }) {
return (
<div>
<h2>intercepting-siblings</h2>
<p id="intercepted-sibling">{id}</p>
</div>
)
}

View file

@ -0,0 +1,3 @@
export default function Default() {
return <div>default</div>
}

View file

@ -0,0 +1,8 @@
export default function Page({ params: { id } }) {
return (
<div>
<h2>main slot</h2>
<p id="main-slot">{id}</p>
</div>
)
}

View file

@ -0,0 +1,29 @@
import Link from 'next/link'
export default function Layout({ children, modal }) {
return (
<div>
<h1>intercepting-siblings</h1>
<div style={{ border: '1px solid black', padding: '1rem' }}>
{children}
</div>
<hr />
<div style={{ border: '1px solid black', padding: '1rem' }}>{modal}</div>
<h1>links</h1>
<ul>
<li>
<Link href="/intercepting-siblings">/intercepting-siblings</Link>
</li>
<li>
<Link href="/intercepting-siblings/1">/intercepting-siblings/1</Link>
</li>
<li>
<Link href="/intercepting-siblings/2">/intercepting-siblings/2</Link>
</li>
<li>
<Link href="/intercepting-siblings/3">/intercepting-siblings/3</Link>
</li>
</ul>
</div>
)
}

View file

@ -0,0 +1,3 @@
export default function Page() {
return <div>main page</div>
}

View file

@ -751,6 +751,42 @@ createNextDescribe(
'intercepted'
)
})
it('should support intercepting local dynamic sibling routes', async () => {
const browser = await next.browser('/intercepting-siblings')
await check(
() =>
browser
.elementByCss('[href="/intercepting-siblings/1"]')
.click()
.waitForElementByCss('#intercepted-sibling')
.text(),
'1'
)
await check(
() =>
browser
.elementByCss('[href="/intercepting-siblings/2"]')
.click()
.waitForElementByCss('#intercepted-sibling')
.text(),
'2'
)
await check(
() =>
browser
.elementByCss('[href="/intercepting-siblings/3"]')
.click()
.waitForElementByCss('#intercepted-sibling')
.text(),
'3'
)
await next.browser('/intercepting-siblings/1')
await check(() => browser.waitForElementByCss('#main-slot').text(), '1')
})
})
}
)