perf(ui): code-split per-window screens so each webview loads only its own code
All 5 webviews (settings/capsule/qa/less-computer/glow) shared one ~942KB bundle, so every WebKit content process parsed+held the entire app (settings UI + LocalAsr 3.4k LOC + Style + Marketplace + chat panels). React.lazy each window root: FloatingShell (settings, 352KB) + QaPanel + LessComputerPanel + LessComputerGlow + Onboarding + AutoUpdateGate are now separate chunks loaded on demand. Capsule kept eager (tiny + latency-sensitive). Secondary webviews no longer load the settings UI → much lower resident memory per process. Frontend-only, build-verified (chunks split, tsc+vite pass). Runtime-sanity: open settings / QA / Less Computer / glow once to confirm they still render (Suspense fallback is blank during first chunk load).
This commit is contained in:
1 parent
3cc4576b12
commit
6aedfb087a
1 file changed
+61
-31
@@ -1,8 +1,5 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { AutoUpdateGate } from './components/AutoUpdateGate';
|
||||
import { lazy, Suspense, useEffect, useState } from 'react';
|
||||
import { Capsule } from './components/Capsule';
|
||||
import { FloatingShell } from './components/FloatingShell';
|
||||
import { Onboarding } from './components/Onboarding';
|
||||
import { detectOS, type OS } from './components/WindowChrome';
|
||||
import {
|
||||
checkAccessibilityPermission,
|
||||
@@ -19,11 +16,30 @@ import {
|
||||
isWindowHotkeyKeyboardCandidate,
|
||||
windowMouseHotkeyCode,
|
||||
} from './lib/windowHotkeyFallback';
|
||||
import { QaPanel } from './pages/QaPanel';
|
||||
import { LessComputerPanel } from './pages/LessComputerPanel';
|
||||
import { LessComputerGlow } from './pages/LessComputerGlow';
|
||||
import { HotkeySettingsProvider } from './state/HotkeySettingsContext';
|
||||
|
||||
// 各窗口/重页面懒加载,让每个 webview 只下载并解析自己用到的那部分代码。原本所有窗口
|
||||
// (主设置 / 胶囊 / QA / Less Computer / glow)共用一个打包产物,导致 5 个常驻 WebKit
|
||||
// 进程都把整套设置 UI(FloatingShell + Style/Marketplace/LocalAsr…)和聊天面板加载进来,
|
||||
// 常驻内存离谱。拆开后胶囊/glow 这类轻窗口不再加载设置/聊天代码。胶囊保持 eager:
|
||||
// 它是听写实时反馈、对首帧延迟敏感,且体积很小。
|
||||
const AutoUpdateGate = lazy(() =>
|
||||
import('./components/AutoUpdateGate').then(m => ({ default: m.AutoUpdateGate })),
|
||||
);
|
||||
const FloatingShell = lazy(() =>
|
||||
import('./components/FloatingShell').then(m => ({ default: m.FloatingShell })),
|
||||
);
|
||||
const Onboarding = lazy(() =>
|
||||
import('./components/Onboarding').then(m => ({ default: m.Onboarding })),
|
||||
);
|
||||
const QaPanel = lazy(() => import('./pages/QaPanel').then(m => ({ default: m.QaPanel })));
|
||||
const LessComputerPanel = lazy(() =>
|
||||
import('./pages/LessComputerPanel').then(m => ({ default: m.LessComputerPanel })),
|
||||
);
|
||||
const LessComputerGlow = lazy(() =>
|
||||
import('./pages/LessComputerGlow').then(m => ({ default: m.LessComputerGlow })),
|
||||
);
|
||||
|
||||
interface AppProps {
|
||||
isCapsule: boolean;
|
||||
isQa: boolean;
|
||||
@@ -40,13 +56,25 @@ export function App({ isCapsule, isQa, isLessComputer, isLessComputerGlow, force
|
||||
return <Capsule />;
|
||||
}
|
||||
if (isQa) {
|
||||
return <QaPanel />;
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<QaPanel />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
if (isLessComputer) {
|
||||
return <LessComputerPanel />;
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<LessComputerPanel />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
if (isLessComputerGlow) {
|
||||
return <LessComputerGlow />;
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<LessComputerGlow />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
const os = forcedOs ?? detectOS();
|
||||
@@ -255,26 +283,28 @@ export function App({ isCapsule, isQa, isLessComputer, isLessComputerGlow, force
|
||||
}, [os]);
|
||||
|
||||
return (
|
||||
<HotkeySettingsProvider>
|
||||
{platformCaps?.platform === 'android' && (
|
||||
<div style={{ display: mobileQaOpen ? 'block' : 'none', height: '100%' }}>
|
||||
<QaPanel
|
||||
embedded
|
||||
onRequestClose={() => {
|
||||
setMobileQaOpen(false);
|
||||
if (window.history.state?.openlessQa === true) {
|
||||
window.history.back();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!mobileQaOpen && (gate === 'onboarding' ? (
|
||||
<Onboarding onComplete={completeOnboarding} />
|
||||
) : (
|
||||
<FloatingShell os={os} />
|
||||
))}
|
||||
{gate === 'ready' && platformCaps?.supportsAutoUpdate === true && <AutoUpdateGate />}
|
||||
</HotkeySettingsProvider>
|
||||
<Suspense fallback={null}>
|
||||
<HotkeySettingsProvider>
|
||||
{platformCaps?.platform === 'android' && (
|
||||
<div style={{ display: mobileQaOpen ? 'block' : 'none', height: '100%' }}>
|
||||
<QaPanel
|
||||
embedded
|
||||
onRequestClose={() => {
|
||||
setMobileQaOpen(false);
|
||||
if (window.history.state?.openlessQa === true) {
|
||||
window.history.back();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!mobileQaOpen && (gate === 'onboarding' ? (
|
||||
<Onboarding onComplete={completeOnboarding} />
|
||||
) : (
|
||||
<FloatingShell os={os} />
|
||||
))}
|
||||
{gate === 'ready' && platformCaps?.supportsAutoUpdate === true && <AutoUpdateGate />}
|
||||
</HotkeySettingsProvider>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user