fix(app): improve session navigation performance - #40427
Conversation
There was a problem hiding this comment.
Pull request overview
Experimental renderer-performance pass focused on reducing startup/module-evaluation cost and eliminating long renderer tasks by shifting heavy parsing/projection work to workers, adding lazy/Suspense boundaries, and bounding unavoidable DOM work across animation frames.
Changes:
- Moved multiple response decoding/projection paths (sessions, home session pages, VCS diffs) to worker-backed ArrayBuffer pipelines to avoid renderer JSON parsing and large structured clones.
- Reduced and bounded renderer work (markdown block commits, Home row reveal batching, prompt cursor parsing) to stay within a small per-frame budget.
- Decomposed startup by lazy-loading UI regions/routes and locale dictionaries; added a real-desktop performance profiling harness and related docs.
Reviewed changes
Copilot reviewed 35 out of 35 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/session-ui/src/v2/components/prompt-input/index.tsx | Reduces prompt-input input/cursor work by computing prompt + cursor in one traversal and limiting cursor updates to navigation keys. |
| packages/session-ui/src/pierre/worker.ts | Switches Pierre worker highlighter preference to avoid renderer WASM startup. |
| packages/session-ui/src/components/markdown.tsx | Commits markdown blocks within an ~8ms per-frame budget and cancels stale render generations. |
| packages/session-ui/src/components/markdown-stream.ts | Simplifies “completed” markdown into bounded top-level blocks when possible (avoids full projection unless refs exist). |
| packages/session-ui/src/components/markdown-stream.test.ts | Adds coverage ensuring completed markdown splits into bounded blocks. |
| packages/desktop/src/renderer/index.tsx | Initializes desktop i18n explicitly during renderer startup. |
| packages/desktop/src/renderer/i18n/index.ts | Converts desktop+app locale loading to lazy/dynamic imports while keeping base dictionary eager. |
| packages/desktop/src/main/index.ts | Adds env-guarded profiling paths (user/session data) and profiling-related Chromium feature/port switches. |
| packages/app/src/utils/vcs-diff-decoder.worker.ts | Adds a dedicated worker entrypoint for VCS diff decoding. |
| packages/app/src/utils/vcs-diff-decoder.ts | Adds worker-backed VCS diff decode with input-idle resolution to reduce perceived typing contention. |
| packages/app/src/utils/vcs-diff-data.ts | Centralizes VCS diff ArrayBuffer→typed diff decoding. |
| packages/app/src/utils/server-compat.ts | Switches legacy session list + VCS diff to ArrayBuffer responses and worker decoders; reuses shared legacy session mapping. |
| packages/app/src/utils/server-compat.test.ts | Wires tests to the new diff/session-list decode hooks. |
| packages/app/src/pages/session.tsx | Requests VCS diff list with context: 0 and strips patches for the list view to reduce payload/work. |
| packages/app/src/pages/layout.tsx | Reduces history prefetch chunk size and removes automatic neighbor warm/sync behavior. |
| packages/app/src/pages/layout-new.tsx | Lazily loads titlebar/help UI with Suspense boundaries to reduce initial entry cost. |
| packages/app/src/pages/home/home-sessions-controller.tsx | Uses projected home session pages (ArrayBuffer decode) and progressively reveals rows in small frame batches. |
| packages/app/src/hooks/use-providers.ts | Enables providers only when the directory-provider hook is actually used. |
| packages/app/src/context/session-message-decoder.worker.ts | Adds a shared worker entrypoint for decoding legacy messages, legacy session lists, and Home session pages. |
| packages/app/src/context/session-message-decoder.ts | Adds worker-backed decode helpers for session messages/lists/home pages. |
| packages/app/src/context/session-message-decode.ts | Implements ArrayBuffer decode/projection for legacy message pages, legacy session lists, and Home page bounding. |
| packages/app/src/context/session-message-decode.test.ts | Adds unit coverage for message/session/home decode and Home directory bounding. |
| packages/app/src/context/server-sync.tsx | Defers global config/path/providers and active-session polling; adds explicit provider enable/load triggers. |
| packages/app/src/context/server-session.ts | Reduces history page size and yields before heavy ingestion; adds optional ArrayBuffer decode path for legacy messages. |
| packages/app/src/context/server-sdk.tsx | Plumbs worker-backed diff/session-list decode into compatible API creation. |
| packages/app/src/context/global-sync/home-session-index.ts | Adds loadProjectedHomeSessionIndex plumbing for pre-projected session pages. |
| packages/app/src/context/global-sync/child-store.ts | Splits provider query enablement from general instance query enablement; adds enableProviders. |
| packages/app/src/context/global-sync/child-store.test.ts | Updates expectations and adds coverage for provider enablement toggling. |
| packages/app/src/context/global-sync/bootstrap.ts | Removes eager providers/config/path fetches from global and directory bootstrap paths. |
| packages/app/src/components/settings-v2/models.tsx | Explicitly triggers provider loading when visiting models settings (v2). |
| packages/app/src/components/settings-models.tsx | Explicitly triggers provider loading when visiting models settings (legacy). |
| packages/app/src/app.tsx | Lazily loads major routes/layouts and the session-ui file renderer to shrink initial entry. |
| packages/app/e2e/regression/session-timeline-history-root.spec.ts | Updates E2E expectation for reduced history page size. |
| packages/app/e2e/performance/real-desktop-profile.ts | Adds a real-desktop DB profiling harness to measure renderer responsiveness and attribution. |
| packages/app/e2e/performance/REAL_DESKTOP_PROFILE.md | Documents the profiling harness, reproduction, and attribution notes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| document.addEventListener( | ||
| "beforeinput", | ||
| () => { | ||
| lastInput = performance.now() | ||
| }, | ||
| { capture: true }, | ||
| ) |
| function resolveWhenInputIdle(resolve: (value: FileDiffInfo[]) => void, value: FileDiffInfo[], initial = true) { | ||
| const active = document.activeElement | ||
| const editing = | ||
| active instanceof HTMLInputElement || | ||
| active instanceof HTMLTextAreaElement || | ||
| (active instanceof HTMLElement && active.isContentEditable) | ||
| const delay = Math.max(lastInput + 100 - performance.now(), initial && editing ? 100 : 0) | ||
| if (delay <= 0) { | ||
| resolve(value) | ||
| return | ||
| } | ||
| setTimeout(() => resolveWhenInputIdle(resolve, value, false), delay) | ||
| } |
|
This PR cannot be merged into the beta branch due to: Merge conflicts with dev branch Please resolve this issue to include this PR in the next beta release. |
2 similar comments
|
This PR cannot be merged into the beta branch due to: Merge conflicts with dev branch Please resolve this issue to include this PR in the next beta release. |
|
This PR cannot be merged into the beta branch due to: Merge conflicts with dev branch Please resolve this issue to include this PR in the next beta release. |
|
This PR cannot be merged into the beta branch due to: Merge failed Please resolve this issue to include this PR in the next beta release. |
1 similar comment
|
This PR cannot be merged into the beta branch due to: Merge failed Please resolve this issue to include this PR in the next beta release. |
|
This PR cannot be merged into the beta branch due to: Merge conflicts with v2 branch Please resolve this issue to include this PR in the next beta release. |
|
How mutch performance improvement should this bring? |
|
This PR cannot be merged into the beta branch due to: Merge failed Please resolve this issue to include this PR in the next beta release. |
Summary
Session navigation now prepares the destination before committing the route. This keeps the current session visible during child-session loading and removes background Markdown work that competed with immediate Home navigation.
The old experimental optimization series was replaced with this three-file change after production benchmarks showed that its lazy-route and Markdown changes no longer improved current
v2.Changes
Production Benchmark
Baseline:
v2at82b96eb495Environment: Windows Chromium, production Vite build, serial execution, five runs per scenario.
Unvisited session, draft, and close-to-Home controls moved by 0 to 12 ms in both directions, which is within the observed machine variance.
Validation