Dashboard: silence benign "Transition was skipped" rejection - #112474
Dashboard: silence benign "Transition was skipped" rejection#112474paulopmt1 wants to merge 1 commit into
Conversation
TanStack Router runs navigations through document.startViewTransition() but discards the returned ViewTransition, so a superseded navigation skips the in-flight transition and its `ready` promise rejects with an uncaught `AbortError: Transition was skipped`. Wrap startViewTransition once at boot so those promises are always handled; only the skip AbortError is swallowed, everything else is re-thrown. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Jetpack Cloud Live (direct link)
Automattic for Agencies Live (direct link)
Dashboard Live (dotcom) (direct link)
|
|
Here is how your PR affects size of JS and CSS bundles shipped to the user's browser: App Entrypoints (~138 bytes added 📈 [gzipped]) DetailsCommon code that is always downloaded and parsed every time the app is loaded, no matter which route is used. Sections (~205 bytes added 📈 [gzipped]) DetailsSections contain code specific for a given set of routes. Is downloaded and parsed only when a particular route is navigated to. Async-loaded Components (~183 bytes added 📈 [gzipped]) DetailsReact components that are loaded lazily, when a certain part of UI is displayed for the first time. Legend What is parsed and gzip size?Parsed Size: Uncompressed size of the JS and CSS files. This much code needs to be parsed and stored in memory. Generated by performance advisor bot at iscalypsofastyet.com. |
Proposed Changes
suppressSkippedViewTransitions(), a small helper that wrapsdocument.startViewTransitiononce so the transition'sready/updateCallbackDone/finishedpromises always have a handler. Only the skipAbortErroris swallowed; any other rejection is re-thrown so real failures stay visible.defaultViewTransition: true):client/dashboard/app/boot.tsx— the standalone Multi-site Dashboard.client/sites/v2/utils/router.ts(getRouterOptions) — the classic-Calypso "Dashboard Backport" routers (site overview / settings / sites list).Why are these changes being made?
Navigating the dashboard logs
Uncaught (in promise) AbortError: Transition was skippedto the console.TanStack Router drives every navigation through
document.startViewTransition()but discards the returnedViewTransition. When a navigation supersedes an in-flight one (rapid filter/search/pagination changes, intent preloading, redirects, or React 19's more-deferred concurrent commits), the browser skips the pending transition and itsreadypromise rejects withAbortError: Transition was skipped. Because the return value is dropped, nothing attaches a handler, so it surfaces as an uncaught rejection.The skip itself is correct browser behavior — only the unhandled rejection is noise. This is not fixed in any released TanStack Router version (the current implementation still drops the return value), so it has to be handled at our layer.
Empirically, on a skipped transition it is specifically the
readypromise that rejects (finished/updateCallbackDoneresolve when the skip happens after the update callback runs), so the helper guards all three and swallows only theAbortError.Testing Instructions
/sites/:slug), which runs the TanStack backport router.Uncaught (in promise) AbortError: Transition was skippedappears in the console.Confirmed live on a Simple site: reproduced the console error on the backport surfaces, and verified that attaching handlers to the transition's promises fully suppresses it while leaving non-
AbortErrorrejections visible.Pre-merge Checklist
🤖 Generated with Claude Code