-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
fix(nuxt): don't trigger scroll when changing trailing slash #33358
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(nuxt): don't trigger scroll when changing trailing slash #33358
Conversation
|
|
@nuxt/kit
nuxt
@nuxt/rspack-builder
@nuxt/schema
@nuxt/vite-builder
@nuxt/webpack-builder
commit: |
CodSpeed Performance ReportMerging #33358 will not alter performanceComparing Summary
|
|
Do I need to include some note in documentation that default behavior has changed ? Is it even mentioned somewhere in the documentation ? |
WalkthroughNormalises paths by removing trailing slashes before comparing Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
danielroe
left a comment
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.
thank you! ❤️
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.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
packages/nuxt/src/app/composables/payload.ts(2 hunks)packages/nuxt/src/core/runtime/nitro/handlers/renderer.ts(2 hunks)packages/nuxt/src/pages/runtime/router.options.ts(1 hunks)test/nuxt/router.options.test.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/nuxt/src/pages/runtime/router.options.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Follow standard TypeScript conventions and best practices
Files:
packages/nuxt/src/core/runtime/nitro/handlers/renderer.tstest/nuxt/router.options.test.tspackages/nuxt/src/app/composables/payload.ts
**/*.{test,spec}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Write unit tests for core functionality using
vitest
Files:
test/nuxt/router.options.test.ts
🧬 Code graph analysis (1)
packages/nuxt/src/core/runtime/nitro/handlers/renderer.ts (2)
packages/nuxt/src/core/runtime/nitro/utils/cache.ts (1)
payloadCache(6-6)packages/nuxt/src/core/runtime/nitro/utils/renderer/payload.ts (1)
renderPayloadResponse(12-24)
🪛 GitHub Actions: autofix.ci
test/nuxt/router.options.test.ts
[error] 35-35: AssertionError: expected "spy" to be called at least once. (nuxt-legacy router.options test: should call scrollTo after page transition is finished with async component)
🪛 GitHub Check: code
test/nuxt/router.options.test.ts
[failure] 35-35: test/nuxt/router.options.test.ts > scrollBehavior of router options with global transition > should call scrollTo after page transition is finished with async component
AssertionError: expected "spy" to be called at least once
❯ completeNavigation test/nuxt/router.options.test.ts:35:28
❯ test/nuxt/router.options.test.ts:84:5
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (4)
packages/nuxt/src/core/runtime/nitro/handlers/renderer.ts (1)
10-10: LGTM! Simplified trailing slash removal.The replacement of
withoutTrailingSlashwith a direct regex pattern.replace(/\/$/, '')is appropriate here. While the ufo helper is more comprehensive (handling edge cases like multiple trailing slashes), the simpler regex suffices for normalised internal URL handling and reduces the dependency footprint.Also applies to: 182-182
packages/nuxt/src/app/composables/payload.ts (1)
1-1: LGTM! Consistent trailing slash normalisation.The change from
withoutTrailingSlash(url)tourl.replace(/\/$/, '')maintains the same behaviour for normalised URLs. SinceisPrerenderedtypically receives paths fromuseRoute().path(already normalised), the simpler regex pattern is sufficient and reduces dependencies.Also applies to: 99-99
test/nuxt/router.options.test.ts (2)
69-80: LGTM! Test correctly validates trailing-slash-agnostic scroll behaviour.The new test properly verifies that navigating between
/aboutand/about/(differing only by a trailing slash) does not triggerscrollToon the second navigation. This correctly validates the PR's objective to make the default router scroll behaviour trailing-slash agnostic.
82-96: LGTM! Test refactoring improves maintainability.Extracting the common navigation completion logic into the
completeNavigationhelper reduces duplication and makes the tests more readable. Once the race condition in the helper is resolved, these tests should function correctly.
| async function completeNavigation () { | ||
| await flushPromises() | ||
|
|
||
| // Ensure everything is settled | ||
| await expect.poll(() => pageTransitionFinish.mock.calls.length).toBeGreaterThan(0) | ||
|
|
||
| expect(pageTransitionFinish).toHaveBeenCalled() | ||
| expect(pageLoadingEnd).toHaveBeenCalled() | ||
| } |
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.
Fix race condition in test helper.
The completeNavigation helper polls for pageTransitionFinish (line 32) but then asserts that both pageTransitionFinish and pageLoadingEnd were called (lines 34-35). This creates a race condition where the assertion for pageLoadingEnd may fail if that hook hasn't been called yet when the poll completes.
Apply this diff to wait for both hooks:
async function completeNavigation () {
await flushPromises()
- // Ensure everything is settled
- await expect.poll(() => pageTransitionFinish.mock.calls.length).toBeGreaterThan(0)
+ // Ensure both transition hooks are called
+ await expect.poll(() => pageTransitionFinish.mock.calls.length).toBeGreaterThan(0)
+ await expect.poll(() => pageLoadingEnd.mock.calls.length).toBeGreaterThan(0)
expect(pageTransitionFinish).toHaveBeenCalled()
expect(pageLoadingEnd).toHaveBeenCalled()
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async function completeNavigation () { | |
| await flushPromises() | |
| // Ensure everything is settled | |
| await expect.poll(() => pageTransitionFinish.mock.calls.length).toBeGreaterThan(0) | |
| expect(pageTransitionFinish).toHaveBeenCalled() | |
| expect(pageLoadingEnd).toHaveBeenCalled() | |
| } | |
| async function completeNavigation () { | |
| await flushPromises() | |
| // Ensure both transition hooks are called | |
| await expect.poll(() => pageTransitionFinish.mock.calls.length).toBeGreaterThan(0) | |
| await expect.poll(() => pageLoadingEnd.mock.calls.length).toBeGreaterThan(0) | |
| expect(pageTransitionFinish).toHaveBeenCalled() | |
| expect(pageLoadingEnd).toHaveBeenCalled() | |
| } |
🧰 Tools
🪛 GitHub Actions: autofix.ci
[error] 35-35: AssertionError: expected "spy" to be called at least once. (nuxt-legacy router.options test: should call scrollTo after page transition is finished with async component)
🪛 GitHub Check: code
[failure] 35-35: test/nuxt/router.options.test.ts > scrollBehavior of router options with global transition > should call scrollTo after page transition is finished with async component
AssertionError: expected "spy" to be called at least once
❯ completeNavigation test/nuxt/router.options.test.ts:35:28
❯ test/nuxt/router.options.test.ts:84:5
🤖 Prompt for AI Agents
In test/nuxt/router.options.test.ts around lines 28 to 36, the
completeNavigation helper currently polls only for pageTransitionFinish before
asserting both hooks, causing a race where pageLoadingEnd may not have been
called yet; change the poll condition to wait until both
pageTransitionFinish.mock.calls.length and pageLoadingEnd.mock.calls.length are
greater than 0 (i.e., poll a function returning that both lengths > 0), keep the
existing flushPromises call before polling, then make the two expect(...)
assertions as-is after the poll completes.
🔗 Linked issue
resolves #33315
📚 Description
When users get to a page, default nuxt router behavior is to compare "from" & "to" path using
===method. Base on that comparison it evaluates whether it should apply scroll-to-top effect or not.However, this comparison is not suitable in case of URLs ending with trailing slash. When navigating from page ending with trailing slash to same page not containing trailing slash at the end, it evaluates the page as being different page and it applies scroll to top effect.
How to reproduce:
It happens even in nuxt website.
Fix Description
My fix is using "ufo" library with function
withoutTrailingSlashwhich will make decision for scroll behavior by default trailing slash agnostic.