From c053e53f18191eb313e5abdf497feeaa94ef1f9e Mon Sep 17 00:00:00 2001
From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
Date: Tue, 20 Oct 2026 11:57:06 -0700
Subject: [PATCH] perf(cmd-j): preload the workspace jump palette before first
use (#30935)
* perf(cmd-j): preload the jump palette so its first open renders without React's reveal delay
* fix: reuse lazy retry wrapper for preloaded components
---
.../src/app-shell/AppRootSurfaces.tsx | 3 +-
.../worktree-jump-palette-preload.ts | 21 ++++++++
.../src/lib/lazy-with-retry.preload.test.tsx | 37 +++++++++++++
src/renderer/src/lib/lazy-with-retry.ts | 52 ++++++++++++++++++-
4 files changed, 111 insertions(+), 2 deletions(-)
create mode 100644 src/renderer/src/app-shell/worktree-jump-palette-preload.ts
create mode 100644 src/renderer/src/lib/lazy-with-retry.preload.test.tsx
diff --git a/src/renderer/src/app-shell/AppRootSurfaces.tsx b/src/renderer/src/app-shell/AppRootSurfaces.tsx
index 983c571f4aa..042b10565f0 100644
--- a/src/renderer/src/app-shell/AppRootSurfaces.tsx
+++ b/src/renderer/src/app-shell/AppRootSurfaces.tsx
@@ -18,6 +18,7 @@ import { shouldRenderPetOverlay } from '../components/pet/pet-overlay-visibility
import { useAppStore } from '../store'
import type { UpdateStatus } from '../../../shared/update-status-types'
import { useLazyModalMounts } from './use-lazy-modal-mounts'
+import { usePreloadWorktreeJumpPalette, WorktreeJumpPalette } from './worktree-jump-palette-preload'
import {
selectAppRootSurfacePetEnabled,
selectAppRootSurfaceTelemetryOptedIn,
@@ -27,7 +28,6 @@ import type { FloatingWorkspacePanelState } from './use-floating-workspace-panel
import type { OnboardingGate } from './use-onboarding-and-feature-tips'
const QuickOpen = lazy(() => import('../components/QuickOpen'))
-const WorktreeJumpPalette = lazy(() => import('../components/WorktreeJumpPalette'))
const WorkspaceCleanupDialog = lazy(
() => import('../components/workspace-cleanup/WorkspaceCleanupDialog')
)
@@ -137,6 +137,7 @@ export function AppRootSurfaces(props: {
}): React.JSX.Element {
const { floatingWorkspace, onboardingGate } = props
const { mountedLazyModalIds, shouldMountAddRepoDialog } = useLazyModalMounts()
+ usePreloadWorktreeJumpPalette()
const activeView = useAppStore((s) => s.activeView)
const activeModal = useAppStore((s) => s.activeModal)
// Keep this always-mounted surface subscribed only to the settings fields it reads. A
diff --git a/src/renderer/src/app-shell/worktree-jump-palette-preload.ts b/src/renderer/src/app-shell/worktree-jump-palette-preload.ts
new file mode 100644
index 00000000000..846be9b5dd6
--- /dev/null
+++ b/src/renderer/src/app-shell/worktree-jump-palette-preload.ts
@@ -0,0 +1,21 @@
+import { useEffect } from 'react'
+import { scheduleAfterInputQuiet } from '@/lib/input-quiet-scheduler'
+import { lazyWithPreload } from '@/lib/lazy-with-retry'
+
+export const WorktreeJumpPalette = lazyWithPreload(
+ () => import('../components/WorktreeJumpPalette')
+)
+
+/** Loads the Cmd+J palette after startup settles so its first open renders without suspending. */
+export function usePreloadWorktreeJumpPalette(): void {
+ useEffect(
+ () =>
+ scheduleAfterInputQuiet(WorktreeJumpPalette.preload, {
+ delayMs: 500,
+ quietMs: 300,
+ idleTimeoutMs: 1_000,
+ maxWaitMs: 2_000
+ }),
+ []
+ )
+}
diff --git a/src/renderer/src/lib/lazy-with-retry.preload.test.tsx b/src/renderer/src/lib/lazy-with-retry.preload.test.tsx
new file mode 100644
index 00000000000..f76223cacb1
--- /dev/null
+++ b/src/renderer/src/lib/lazy-with-retry.preload.test.tsx
@@ -0,0 +1,37 @@
+// @vitest-environment happy-dom
+import { act, Suspense } from 'react'
+import { createRoot } from 'react-dom/client'
+import { describe, expect, it, vi } from 'vitest'
+
+import { lazyWithPreload } from './lazy-with-retry'
+
+Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true })
+
+function Palette(): React.JSX.Element {
+ return
+}
+
+describe('lazyWithPreload', () => {
+ it('renders a preloaded component in the same commit, without the Suspense fallback', async () => {
+ const factory = vi.fn(() => Promise.resolve({ default: Palette }))
+ const Preloadable = lazyWithPreload(factory)
+ Preloadable.preload()
+ await act(async () => {})
+
+ const container = document.createElement('div')
+ const root = createRoot(container)
+ // A synchronous act flushes one render with no chance to retry a suspended one.
+ act(() => {
+ root.render(
+ loading}>
+
+
+ )
+ })
+
+ expect(container.querySelector('input[aria-label="palette"]')).not.toBeNull()
+ expect(container.textContent).not.toContain('loading')
+ expect(factory).toHaveBeenCalledTimes(1)
+ act(() => root.unmount())
+ })
+})
diff --git a/src/renderer/src/lib/lazy-with-retry.ts b/src/renderer/src/lib/lazy-with-retry.ts
index 77650b67ded..a19ad4063a8 100644
--- a/src/renderer/src/lib/lazy-with-retry.ts
+++ b/src/renderer/src/lib/lazy-with-retry.ts
@@ -1,4 +1,12 @@
-import { lazy, type ComponentType, type LazyExoticComponent } from 'react'
+import {
+ createElement,
+ lazy,
+ useState,
+ type ComponentProps,
+ type ComponentType,
+ type LazyExoticComponent,
+ type ReactNode
+} from 'react'
import {
requestLazyChunkRecoveryReload,
@@ -256,3 +264,45 @@ export function lazyWithRetry(
): LazyExoticComponent {
return lazy(() => loadLazyWithRetry(factory, options))
}
+
+export type PreloadableLazyComponent = ComponentType> & {
+ /** Loads the chunk ahead of first render; failures stay silent so the real render owns recovery. */
+ preload: () => void
+}
+
+/**
+ * lazyWithRetry plus preload(). Once preloaded, the component renders the loaded module
+ * directly instead of through React.lazy, so its first render never suspends: React holds
+ * a newly resolved Suspense reveal for up to 300 ms, which is what made first opens slow.
+ */
+export function lazyWithPreload(
+ factory: LazyFactory,
+ options?: LazyWithRetryOptions
+): PreloadableLazyComponent {
+ let loaded: T | null = null
+ const LazyComponent = lazyWithRetry(
+ () =>
+ factory().then((module) => {
+ loaded ??= module.default
+ return module
+ }),
+ options
+ )
+ function PreloadableComponent(props: ComponentProps): ReactNode {
+ // Why: pinned per mount so a module resolving mid-life cannot swap the element type and remount the subtree.
+ const [Component] = useState(() => loaded ?? LazyComponent)
+ return createElement(Component, props)
+ }
+ PreloadableComponent.preload = (): void => {
+ if (loaded) {
+ return
+ }
+ factory().then(
+ (module) => {
+ loaded ??= module.default
+ },
+ () => undefined
+ )
+ }
+ return PreloadableComponent
+}