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
This commit is contained in:
Brennan Benson
2026-10-20 11:57:06 -07:00
committed by GitHub
parent ad1bcfe502
commit c053e53f18
4 changed files with 111 additions and 2 deletions
@@ -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
@@ -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
}),
[]
)
}
@@ -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 <input aria-label="palette" />
}
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(
<Suspense fallback={<span>loading</span>}>
<Preloadable />
</Suspense>
)
})
expect(container.querySelector('input[aria-label="palette"]')).not.toBeNull()
expect(container.textContent).not.toContain('loading')
expect(factory).toHaveBeenCalledTimes(1)
act(() => root.unmount())
})
})
+51 -1
View File
@@ -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<T extends AnyComponent>(
): LazyExoticComponent<T> {
return lazy(() => loadLazyWithRetry(factory, options))
}
export type PreloadableLazyComponent<T extends AnyComponent> = ComponentType<ComponentProps<T>> & {
/** 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<T extends AnyComponent>(
factory: LazyFactory<T>,
options?: LazyWithRetryOptions
): PreloadableLazyComponent<T> {
let loaded: T | null = null
const LazyComponent = lazyWithRetry(
() =>
factory().then((module) => {
loaded ??= module.default
return module
}),
options
)
function PreloadableComponent(props: ComponentProps<T>): 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
}