mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[GH-ISSUE #652] Cross-route client navigation hangs in Firefox (startTransition never commits) #137
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#137
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @NathanDrake2406 on GitHub (Mar 22, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/652
Description
Cross-route client-side navigation (e.g.
/topto/tv-shows) hangs indefinitely in Firefox. The old page stays visible and the new page never renders. Same-route navigations (e.g. changing searchParams on/top) work fine in all browsers.This is Firefox-specific and only reproduces on production builds served via
wrangler dev(workerd). Chrome works fine for all navigation types.Root cause
React's
startTransitionnever commits when the entire component tree is replaced during a cross-route navigation in Firefox. The transition render starts but React never calls the commit phase, souseLayoutEffectcallbacks never fire and the navigation promise never resolves.This is not a React bug. Next.js avoids this entirely because their segment-level cache architecture only swaps changed route segments inside
startTransition-- parent layouts stay mounted, so the transition is always an incremental update. vinext replaces the full RSC tree on every cross-route navigation, which is a much larger update that React's transition scheduler apparently cannot finalize in Firefox.Investigation trace (with debug logging in the browser entry):
navigateImplis callednavigateRscfetches the RSC response (200 OK, valid payload)renderNavigationPayloadcallsstartTransition(() => setState({...}))No React errors are reported via
onUncaughtErrororonRecoverableErrorcallbacks on the root.Proper fix
Implement segment-level caching (a
CacheNodetree that mirrors route segments). On navigation, diff the old and new route trees and only swap segments that changed. This would makestartTransitionupdates incremental (matching Next.js behavior) and eliminate the Firefox hang.See analysis in #639 for details on how Next.js handles this via
layout-router.tsx+segment-cache/navigation.ts.Workaround
PR #643 works around this by detecting cross-route vs same-route navigations and only using
startTransitionfor same-route navigations. Cross-route navigations use synchronous state updates, which commit immediately in all browsers:This means cross-route navigations lose the "keep old UI visible during loading" behavior, but the page navigates. Same-route navigations (filter changes) still benefit from transitions.
Reproduction
wrangler devEnvironment
wrangler dev[plugin rsc:use-client] unsupported ExportAllDeclaration#182