-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
fix(nuxt): align scroll behavior with page transition completion #32239
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
Conversation
|
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.
Pull Request Overview
This PR aligns scroll behavior with page transition completion by moving the transition state flag assignment to an earlier lifecycle hook.
- Removed the onBeforeLeave hook that previously set nuxtApp._runningTransition.
- Updated the onPending hook to conditionally set nuxtApp._runningTransition when a transition is present and then call the page:start hook.
@@ -169,7 +166,10 @@ export default defineComponent({ | |||
vnode = _wrapInTransition(hasTransition && transitionProps, | |||
wrapInKeepAlive(keepaliveConfig, h(Suspense, { | |||
suspensible: true, | |||
onPending: () => nuxtApp.callHook('page:start', routeProps.Component), | |||
onPending: () => { |
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.
Consider adding an inline comment that explains the rationale for conditionally setting nuxtApp._runningTransition in the onPending hook based on the hasTransition flag, to improve maintainability.
Copilot uses AI. Check for mistakes.
WalkthroughThe update modifies the handling of the internal ✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
@nuxt/kit
nuxt
@nuxt/rspack-builder
@nuxt/schema
@nuxt/vite-builder
@nuxt/webpack-builder
commit: |
CodSpeed Performance ReportMerging #32239 will not alter performanceComparing Summary
|
Looks promising - hope it will finally fix the issue :-) |
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.
I would love to have a test for this... (as there is a matrix of scroll behaviour and I'd like this not to break again)
ideally a nuxt runtime test rather than an e2e test (which can be notoriously flaky on scroll).
…t into fix/align-scroll-behavior
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: 0
🧹 Nitpick comments (5)
test/nuxt/router.option.test.ts (5)
13-24
: Consider making the sleep duration configurable and increasing the waitFor timeout.The hardcoded 10ms sleep duration may be insufficient for testing realistic async behaviour, and the 1000ms timeout could cause flaky tests in CI environments.
-const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) +const sleep = (ms: number = 50) => new Promise(resolve => setTimeout(resolve, ms)) -const waitFor = async (condition: () => boolean, timeout = 1000) => { +const waitFor = async (condition: () => boolean, timeout = 5000) => {
32-52
: Extract component definitions to improve test readability.The inline component definitions make the addRoute function complex. Consider extracting them for better maintainability.
+const createSyncComponent = () => defineComponent({ + name: '~/pages/[...slug].vue', + setup: () => () => h('div'), +}) + +const createAsyncComponent = () => defineComponent({ + name: '~/pages/[...slug].vue', + async setup() { + await sleep(50) + return () => h('div') + }, +}) const addRoute = (sync: boolean) => { router.addRoute({ name: 'slug', path: '/:slug(.*)*', - component: defineComponent({ - name: '~/pages/[...slug].vue', - ...(sync - ? { - setup: () => () => h('div'), - } - : { - async setup () { - await sleep(10) - return () => h('div') - }, - } - ), - }), + component: sync ? createSyncComponent() : createAsyncComponent(), }) }
58-62
: Enhance cleanup to prevent test interference.The current cleanup may not fully reset the router state, potentially causing test interference.
afterEach(() => { + // Clear any pending navigation + router.replace('/') router.removeRoute('slug') vi.clearAllMocks() scrollTo.mockClear() + // Clear any registered hooks + nuxtApp.hooks.clear() })
96-126
: Consider consolidating duplicate test logic.Both test cases share nearly identical setup and assertions. Extract common logic to reduce duplication.
+const runScrollBehaviorTest = async (useAsyncComponent: boolean) => { + addRoute(!useAsyncComponent) + + await mountSuspended({ + setup: () => () => h(NuxtPage, { + transition: { + name: 'fade', + mode: 'out-in', + duration: 10, + }, + }), + }) + + await flushPromises() + + const pageTransitionFinish = vi.fn() + const pageLoadingEnd = vi.fn() + + nuxtApp.hook('page:transition:finish', pageTransitionFinish) + nuxtApp.hook('page:loading:end', pageLoadingEnd) + + await router.push('/page') + await waitFor(() => pageTransitionFinish.mock.calls.length > 0) + + expect(pageTransitionFinish).toHaveBeenCalled() + expect(pageLoadingEnd).toHaveBeenCalled() + expect(scrollTo).toHaveBeenCalled() + expect(pageTransitionFinish).toHaveBeenCalledBefore(scrollTo) +} it('should call scrollTo after page transition is finished with async component', async () => { - addRoute(false) - // ... rest of test logic + await runScrollBehaviorTest(true) }) it('should call scrollTo after page transition is finished with sync component', async () => { - addRoute(true) - // ... rest of test logic + await runScrollBehaviorTest(false) })
67-75
: Transition duration may be too short for reliable testing.The 10ms transition duration could cause timing issues in slower test environments.
transition: { name: 'fade', mode: 'out-in', - duration: 10, + duration: 100, },
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
test/nuxt/router.option.test.ts
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: codeql (javascript-typescript)
- GitHub Check: code
- GitHub Check: semantic-pr
🔇 Additional comments (2)
test/nuxt/router.option.test.ts (2)
1-11
: Test configuration and imports look appropriate.The imports correctly include the necessary testing utilities and the transition stub configuration properly allows actual transition behaviour to be tested.
64-94
: Test correctly validates async component scroll behaviour.The test properly verifies that scrollTo is called after page transition completion, which aligns with the PR objective of fixing scroll behaviour timing with async components.
🔗 Linked issue
Related(?) #32053
Resolve #32193
📚 Description
In #31914, we used the
<Transition>
component’sonBeforeLeave
hook to record whether a page transition is in progress, allowingrouter.options.ts
to determine which hook to wait for before performing scroll behavior.Originally, the sequence of events was as follows:
However, when a page component uses
<script setup>
with top-levelawait
expressions or anasync setup()
function, the event order changes to:In this case, since
<Transition>
’sonBeforeLeave
is triggered afterrouter.options.ts
, make scroll logic cannot correctly determine whether a transition is in progress.This PR moves the transition state tracking into the
onPending
hook of<Suspense>
. I hope this adjustment ensures that scroll behavior remains correctly.👉 #32193 fixed reproduction