Skip to content

Dashboard: silence benign "Transition was skipped" rejection - #112474

Draft
paulopmt1 wants to merge 1 commit into
trunkfrom
fix/skipped-view-transition-rejection
Draft

Dashboard: silence benign "Transition was skipped" rejection#112474
paulopmt1 wants to merge 1 commit into
trunkfrom
fix/skipped-view-transition-rejection

Conversation

@paulopmt1

Copy link
Copy Markdown
Contributor

Proposed Changes

  • Add suppressSkippedViewTransitions(), a small helper that wraps document.startViewTransition once so the transition's ready / updateCallbackDone / finished promises always have a handler. Only the skip AbortError is swallowed; any other rejection is re-thrown so real failures stay visible.
  • Call it from the two boot paths that enable TanStack Router view transitions (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 skipped to the console.

TanStack Router drives every navigation through document.startViewTransition() but discards the returned ViewTransition. 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 its ready promise rejects with AbortError: 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 ready promise that rejects (finished / updateCallbackDone resolve when the skip happens after the update callback runs), so the helper guards all three and swallows only the AbortError.

Testing Instructions

  1. Log into a WordPress.com sandbox and open a site's overview/settings (/sites/:slug), which runs the TanStack backport router.
  2. Open DevTools → Console.
  3. Navigate rapidly between the site menu tabs (Overview / Monitoring / Logs / Settings) and hover site rows to trigger intent preloading.
  4. Before this change: Uncaught (in promise) AbortError: Transition was skipped appears in the console.
  5. After this change: the message no longer appears; navigation and animations are otherwise unchanged.

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-AbortError rejections visible.

Note: local yarn typecheck-client / yarn lint were not run — this branch is an emdash worktree without node_modules. The change is a small, type-safe addition; CI's type_check_client covers it.

Pre-merge Checklist

  • Has the general commit checklist been followed? (PCYsg-hS-p2)
  • Have you written new tests for your changes?
  • Have you tested the feature in Simple (P9HQHe-k8-p2), Atomic (P9HQHe-jW-p2), and self-hosted Jetpack sites (PCYsg-g6b-p2)?
  • Have you checked for TypeScript, React or other console errors?
  • For UI changes, have you tested the affected components in dark mode?
  • Have you tested accessibility for your changes?
  • Have you used memoizing on expensive computations?
  • Have we added the "[Status] String Freeze" label as soon as any new strings were ready for translation (p4TIVU-5Jq-p2)?
  • For changes affecting Jetpack: Have we added the "[Status] Needs Privacy Updates" label (p4TIVU-aUh-p2)?

🤖 Generated with Claude Code

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>
@matticbot

Copy link
Copy Markdown
Contributor

Here is how your PR affects size of JS and CSS bundles shipped to the user's browser:

App Entrypoints (~138 bytes added 📈 [gzipped])

Details
name                    parsed_size           gzip_size
entry-dashboard-dotcom       +534 B  (+0.0%)     +138 B  (+0.0%)
entry-dashboard-ciab         +534 B  (+0.0%)     +138 B  (+0.0%)
entry-dashboard-a4a          +534 B  (+0.0%)     +138 B  (+0.0%)

Common code that is always downloaded and parsed every time the app is loaded, no matter which route is used.

Sections (~205 bytes added 📈 [gzipped])

Details
name             parsed_size           gzip_size
sites-dashboard       +532 B  (+0.0%)     +205 B  (+0.0%)
site-settings         +532 B  (+0.0%)     +205 B  (+0.0%)
overview              +532 B  (+0.0%)     +205 B  (+0.0%)
hosting               +532 B  (+0.0%)     +205 B  (+0.0%)

Sections 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])

Details
name                                    parsed_size           gzip_size
async-load-calypso-sites-v2-sites-list       +532 B  (+2.0%)     +183 B  (+2.9%)

React 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.
Gzip Size: Compressed size of the JS and CSS files. This much data needs to be downloaded over network.

Generated by performance advisor bot at iscalypsofastyet.com.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants