From 6aedfb087ac15ca2eb442c455d2dfefdcc8d1781 Mon Sep 17 00:00:00 2001 From: Andy Jiang <72869031+jiangmuran@users.noreply.github.com> Date: Sun, 14 Jun 2026 13:57:40 +0800 Subject: [PATCH] perf(ui): code-split per-window screens so each webview loads only its own code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- openless-all/app/src/App.tsx | 92 ++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 31 deletions(-) diff --git a/openless-all/app/src/App.tsx b/openless-all/app/src/App.tsx index 79c60f76..28bdb085 100644 --- a/openless-all/app/src/App.tsx +++ b/openless-all/app/src/App.tsx @@ -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 ; } if (isQa) { - return ; + return ( + + + + ); } if (isLessComputer) { - return ; + return ( + + + + ); } if (isLessComputerGlow) { - return ; + return ( + + + + ); } const os = forcedOs ?? detectOS(); @@ -255,26 +283,28 @@ export function App({ isCapsule, isQa, isLessComputer, isLessComputerGlow, force }, [os]); return ( - - {platformCaps?.platform === 'android' && ( -
- { - setMobileQaOpen(false); - if (window.history.state?.openlessQa === true) { - window.history.back(); - } - }} - /> -
- )} - {!mobileQaOpen && (gate === 'onboarding' ? ( - - ) : ( - - ))} - {gate === 'ready' && platformCaps?.supportsAutoUpdate === true && } -
+ + + {platformCaps?.platform === 'android' && ( +
+ { + setMobileQaOpen(false); + if (window.history.state?.openlessQa === true) { + window.history.back(); + } + }} + /> +
+ )} + {!mobileQaOpen && (gate === 'onboarding' ? ( + + ) : ( + + ))} + {gate === 'ready' && platformCaps?.supportsAutoUpdate === true && } +
+
); }