Fix browser navigation buttons not working with shallow routing and middleware (#43919)
This PR fixes #41064. In some particular cases, while using a middleware and shallow routing the navigation get stucks and stop refreshing the page. After futher investigation it seems that a line of code was added that causes the router pathname to be incorrect and then making Next believe it's the same page that is loading. ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [x] Errors have a helpful link attached, see [`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md) ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] [e2e](https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have a helpful link attached, see [`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md) ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm build && pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) Co-authored-by: JJ Kasper <jj@jjsweb.site>
This commit is contained in:
parent
be90c0b909
commit
a34b20e6f2
5 changed files with 109 additions and 9 deletions
|
@ -1456,15 +1456,13 @@ export default class Router implements BaseRouter {
|
|||
|
||||
// we don't attempt resolve asPath when we need to execute
|
||||
// middleware as the resolving will occur server-side
|
||||
const isMiddlewareMatch = await matchesMiddleware({
|
||||
asPath: as,
|
||||
locale: nextState.locale,
|
||||
router: this,
|
||||
})
|
||||
|
||||
if (options.shallow && isMiddlewareMatch) {
|
||||
pathname = this.pathname
|
||||
}
|
||||
const isMiddlewareMatch =
|
||||
!options.shallow &&
|
||||
(await matchesMiddleware({
|
||||
asPath: as,
|
||||
locale: nextState.locale,
|
||||
router: this,
|
||||
}))
|
||||
|
||||
if (isQueryUpdating && isMiddlewareMatch) {
|
||||
shouldResolveHref = false
|
||||
|
|
9
test/e2e/middleware-shallow-link/app/middleware.js
Normal file
9
test/e2e/middleware-shallow-link/app/middleware.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { NextResponse } from 'next/server'
|
||||
|
||||
export async function middleware() {
|
||||
return NextResponse.next()
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: '/(.*$)',
|
||||
}
|
26
test/e2e/middleware-shallow-link/app/pages/index.js
Normal file
26
test/e2e/middleware-shallow-link/app/pages/index.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<>
|
||||
<h1>Content for page 1</h1>
|
||||
<div>
|
||||
<Link
|
||||
data-next-shallow-push
|
||||
shallow
|
||||
href={{ query: { params: 'testParams' } }}
|
||||
>
|
||||
Shallow push
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link data-next-page href="/page2">
|
||||
Go to page 2
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Page
|
25
test/e2e/middleware-shallow-link/app/pages/page2.js
Normal file
25
test/e2e/middleware-shallow-link/app/pages/page2.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<>
|
||||
<h1>Content for page 2</h1>
|
||||
<Link
|
||||
data-next-shallow-replace
|
||||
replace
|
||||
shallow
|
||||
href={{ query: { params: 'testParams' } }}
|
||||
>
|
||||
Shallow replace
|
||||
</Link>
|
||||
<div>
|
||||
<button data-go-back onClick={() => window.history.back()}>
|
||||
Go Back
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Page
|
42
test/e2e/middleware-shallow-link/index.test.ts
Normal file
42
test/e2e/middleware-shallow-link/index.test.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { createNext, FileRef } from 'e2e-utils'
|
||||
import { NextInstance } from 'test/lib/next-modes/base'
|
||||
import webdriver from 'next-webdriver'
|
||||
import { join } from 'path'
|
||||
|
||||
describe('browser-shallow-navigation', () => {
|
||||
let next: NextInstance
|
||||
|
||||
beforeAll(async () => {
|
||||
next = await createNext({
|
||||
files: {
|
||||
pages: new FileRef(join(__dirname, 'app/pages')),
|
||||
'middleware.js': new FileRef(join(__dirname, 'app/middleware.js')),
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(() => next.destroy())
|
||||
|
||||
it('should render the correct page', async () => {
|
||||
const browser = await webdriver(next.url, '/')
|
||||
|
||||
/// do shallow push
|
||||
await browser.elementByCss('[data-next-shallow-push]').click()
|
||||
await browser.waitForElementByCss('[data-next-page]')
|
||||
|
||||
// go to another page
|
||||
await browser.elementByCss('[data-next-page]').click()
|
||||
await browser.waitForElementByCss('[data-next-shallow-replace]')
|
||||
|
||||
// do shadow replace
|
||||
await browser.elementByCss('[data-next-shallow-replace]').click()
|
||||
await browser.waitForElementByCss('[data-go-back]')
|
||||
|
||||
// go back using history api
|
||||
await browser.elementByCss('[data-go-back]').click()
|
||||
|
||||
// get page h1
|
||||
let title = await browser.elementByCss('h1').text()
|
||||
expect(title).toContain('Content for page 1')
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue