perf: reduce duplicate app initialization and heavy view imports

Deduplicates concurrent app initialization in the config store
Lazy-loads VS Code-only app surfaces
Avoids broad view barrel imports for better chunk isolation
This commit is contained in:
Bohdan Triapitsyn
2026-05-06 02:43:13 +03:00
parent 170d334921
commit dbc06dd6fa
7 changed files with 71 additions and 79 deletions
+23 -38
View File
@@ -1,8 +1,6 @@
import React from 'react';
import { MainLayout } from '@/components/layout/MainLayout';
import { VSCodeLayout } from '@/components/layout/VSCodeLayout';
import { AgentManagerView } from '@/components/views/agent-manager';
import { ChatView } from '@/components/views';
import { ChatView } from '@/components/views/ChatView';
import { FireworksProvider } from '@/contexts/FireworksContext';
import { Toaster } from '@/components/ui/sonner';
import { Button } from '@/components/ui/button';
@@ -65,6 +63,14 @@ const OnboardingScreen = lazyWithChunkRecovery(() =>
import('@/components/onboarding/OnboardingScreen').then((m) => ({ default: m.OnboardingScreen })),
);
const VSCodeLayoutLazy = lazyWithChunkRecovery(() =>
import('@/components/layout/VSCodeLayout').then((m) => ({ default: m.VSCodeLayout })),
);
const AgentManagerViewLazy = lazyWithChunkRecovery(() =>
import('@/components/views/agent-manager').then((m) => ({ default: m.AgentManagerView })),
);
const AboutDialogWrapper: React.FC = () => {
const isAboutDialogOpen = useUIStore((s) => s.isAboutDialogOpen);
const setAboutDialogOpen = useUIStore((s) => s.setAboutDialogOpen);
@@ -236,7 +242,6 @@ function App({ apis }: AppProps) {
: null;
});
const appReadyDispatchedRef = React.useRef(false);
const initializationInFlightRef = React.useRef(false);
const embeddedSessionChat = React.useMemo<EmbeddedSessionChatConfig | null>(() => readEmbeddedSessionChatConfig(), []);
const embeddedBackgroundWorkEnabled = !embeddedSessionChat || isEmbeddedVisible;
const isMcpOAuthCallback = React.useMemo(() => isMcpOAuthCallbackPath(), []);
@@ -383,24 +388,12 @@ function App({ apis }: AppProps) {
}, [setPlanModeEnabled]);
React.useEffect(() => {
const init = async () => {
// VS Code runtime bootstraps config + sessions after the managed OpenCode instance reports "connected".
// Doing the default initialization here can race with startup and lead to one-shot failures.
if (isVSCodeRuntime) {
return;
}
if (initializationInFlightRef.current) {
return;
}
initializationInFlightRef.current = true;
try {
await initializeApp();
} finally {
initializationInFlightRef.current = false;
}
};
init();
// VS Code runtime bootstraps config + sessions after the managed OpenCode instance reports "connected".
// Doing the default initialization here can race with startup and lead to one-shot failures.
if (isVSCodeRuntime) {
return;
}
void initializeApp();
}, [initializeApp, isVSCodeRuntime]);
React.useEffect(() => {
@@ -423,18 +416,8 @@ function App({ apis }: AppProps) {
setInitRetryExhausted(false);
return;
}
if (initializationInFlightRef.current) {
retryTimer = setTimeout(retryInitialization, BASE_DELAY_MS);
return;
}
retryCount += 1;
initializationInFlightRef.current = true;
try {
await state.initializeApp();
} finally {
initializationInFlightRef.current = false;
}
await state.initializeApp();
const next = useConfigStore.getState();
if (!active) return;
@@ -760,15 +743,13 @@ function App({ apis }: AppProps) {
}, []);
const handleManualInitRetry = React.useCallback(async () => {
if (manualInitRetrying || initializationInFlightRef.current) return;
if (manualInitRetrying) return;
setInitRetryExhausted(false);
setManualInitRetrying(true);
initializationInFlightRef.current = true;
try {
await useConfigStore.getState().initializeApp();
} finally {
initializationInFlightRef.current = false;
setManualInitRetrying(false);
}
@@ -882,7 +863,9 @@ function App({ apis }: AppProps) {
<TooltipProvider delayDuration={300} skipDelayDuration={150}>
<div className="h-full text-foreground bg-background">
<SyncAppEffects embeddedBackgroundWorkEnabled={embeddedBackgroundWorkEnabled} />
<AgentManagerView />
<React.Suspense fallback={<div className="h-full" />}>
<AgentManagerViewLazy />
</React.Suspense>
<Toaster />
</div>
</TooltipProvider>
@@ -900,7 +883,9 @@ function App({ apis }: AppProps) {
<TooltipProvider delayDuration={300} skipDelayDuration={150}>
<div className="h-full text-foreground bg-background">
<SyncAppEffects embeddedBackgroundWorkEnabled={embeddedBackgroundWorkEnabled} />
<VSCodeLayout />
<React.Suspense fallback={<div className="h-full" />}>
<VSCodeLayoutLazy />
</React.Suspense>
<Toaster />
</div>
</TooltipProvider>
@@ -4,7 +4,9 @@ import { RiArrowLeftRightLine, RiChat4Line, RiCloseLine, RiDonutChartFill, RiFil
import { FileTypeIcon } from '@/components/icons/FileTypeIcon';
import { Button } from '@/components/ui/button';
import { SortableTabsStrip } from '@/components/ui/sortable-tabs-strip';
import { DiffView, FilesView, PlanView } from '@/components/views';
import { DiffView } from '@/components/views/DiffView';
import { FilesView } from '@/components/views/FilesView';
import { PlanView } from '@/components/views/PlanView';
import { useThemeSystem } from '@/contexts/useThemeSystem';
import { openExternalUrl } from '@/lib/url';
import { copyTextToClipboard } from '@/lib/clipboard';
@@ -25,7 +25,7 @@ import { cn } from '@/lib/utils';
import { isDesktopShell } from '@/lib/desktop';
import { lazyWithChunkRecovery } from '@/lib/chunkLoadRecovery';
import { ChatView } from '@/components/views';
import { ChatView } from '@/components/views/ChatView';
// Heavy views loaded on-demand to reduce initial bundle parse time.
const PlanView = lazyWithChunkRecovery(() => import('@/components/views/PlanView').then(m => ({ default: m.PlanView })));
@@ -3,7 +3,7 @@ import { RiBookletLine, RiFolder3Line, RiGitBranchLine } from '@remixicon/react'
import { SortableTabsStrip } from '@/components/ui/sortable-tabs-strip';
import { ProjectNotesTodoPanel } from '@/components/session/ProjectNotesTodoPanel';
import { GitView } from '@/components/views';
import { GitView } from '@/components/views/GitView';
import { useGitStore } from '@/stores/useGitStore';
import { useProjectsStore } from '@/stores/useProjectsStore';
import { useDirectoryStore } from '@/stores/useDirectoryStore';
@@ -1,7 +1,7 @@
import React from 'react';
import { ErrorBoundary } from '../ui/ErrorBoundary';
import { SessionSidebar } from '@/components/session/SessionSidebar';
import { ChatView } from '@/components/views';
import { ChatView } from '@/components/views/ChatView';
import { useSessionUIStore } from '@/sync/session-ui-store';
import { useViewportStore } from '@/sync/viewport-store';
import { useSessions, useDirectorySync, useSessionMessages, useSessionMessagesResolved } from '@/sync/sync-context';
+1 -8
View File
@@ -1,9 +1,2 @@
/** Entry-level views only. Avoid barrel re-exports that pull heavy modules into the main chunk. */
export { ChatView } from './ChatView';
export { PlanView } from './PlanView';
export { GitView } from './GitView';
export { DiffView, useDiffFileCount } from './DiffView';
export { TerminalView } from './TerminalView';
export { FilesView } from './FilesView';
export { SettingsView } from './SettingsView';
export { SettingsWindow } from './SettingsWindow';
export { MultiRunWindow } from './MultiRunWindow';
+41 -29
View File
@@ -583,6 +583,7 @@ declare global {
// In-flight dedup: prevent concurrent duplicate loadProviders/loadAgents calls for the same directory
const _inFlightProviders = new Map<string, Promise<void>>();
const _inFlightAgents = new Map<string, Promise<boolean>>();
let _initializeAppInFlight: Promise<void> | null = null;
export const useConfigStore = create<ConfigStore>()(
devtools(
@@ -1965,43 +1966,54 @@ export const useConfigStore = create<ConfigStore>()(
},
initializeApp: async () => {
try {
const debug = streamDebugEnabled();
if (debug) console.log("Starting app initialization...");
if (_initializeAppInFlight) {
return _initializeAppInFlight;
}
const isConnected = await get().checkConnection();
if (debug) console.log("Connection check result:", isConnected);
const run = (async () => {
try {
const debug = streamDebugEnabled();
if (debug) console.log("Starting app initialization...");
if (!isConnected) {
if (debug) console.log("Server not connected");
// checkConnection already set lastDisconnectReason; do not overwrite.
const isConnected = await get().checkConnection();
if (debug) console.log("Connection check result:", isConnected);
if (!isConnected) {
if (debug) console.log("Server not connected");
// checkConnection already set lastDisconnectReason; do not overwrite.
set({
isConnected: false,
connectionPhase: get().hasEverConnected ? "reconnecting" : "connecting",
});
return;
}
if (debug) console.log("Initializing app...");
await opencodeClient.initApp();
if (debug) console.log("Loading providers...");
await get().loadProviders();
if (debug) console.log("Loading agents...");
await get().loadAgents();
set({ isInitialized: true, isConnected: true, hasEverConnected: true, connectionPhase: "connected" });
if (debug) console.log("App initialized successfully");
} catch (error) {
console.error("Failed to initialize app:", error);
set({
isInitialized: false,
isConnected: false,
connectionPhase: get().hasEverConnected ? "reconnecting" : "connecting",
lastDisconnectReason: 'init_error',
});
return;
}
})().finally(() => {
_initializeAppInFlight = null;
});
if (debug) console.log("Initializing app...");
await opencodeClient.initApp();
if (debug) console.log("Loading providers...");
await get().loadProviders();
if (debug) console.log("Loading agents...");
await get().loadAgents();
set({ isInitialized: true, isConnected: true, hasEverConnected: true, connectionPhase: "connected" });
if (debug) console.log("App initialized successfully");
} catch (error) {
console.error("Failed to initialize app:", error);
set({
isInitialized: false,
isConnected: false,
connectionPhase: get().hasEverConnected ? "reconnecting" : "connecting",
lastDisconnectReason: 'init_error',
});
}
_initializeAppInFlight = run;
return run;
},
getCurrentProvider: () => {