Skip to content

perf(desktop): code-split the four drawable panels via React.lazy#3116

Open
HUQIANTAO wants to merge 1 commit into
esengine:main-v2from
HUQIANTAO:perf/lazy-panels
Open

perf(desktop): code-split the four drawable panels via React.lazy#3116
HUQIANTAO wants to merge 1 commit into
esengine:main-v2from
HUQIANTAO:perf/lazy-panels

Conversation

@HUQIANTAO

Copy link
Copy Markdown
Contributor

Memory, History, Settings, and the Update banner are opened via state toggles and are mutually exclusive in practice. They each pull in their own transitive deps. Convert each import to React.lazy() with a Suspense boundary. Each panel's JS chunk is fetched on first render (the first time the user clicks the corresponding topbar chip), so the initial bundle loses those four trees and any of their imports.

The fallback is null because the panels themselves are modal drawers with their own loading state. The .then(m => ({ default: m.X })) adapter handles modules whose named export is the public surface (per CodeViewer's 'editor seam' pattern).

@github-actions github-actions Bot added the v2 Go rewrite (1.x) — main-v2 branch, active development label Jun 4, 2026
Memory, History, Settings, and the Update banner are all opened via
state toggles and are mutually exclusive in practice. They each pull
in their own transitive deps (e.g. the history drawer imports the
session-row subcomponent; the settings panel imports the dict-derived
section components; the memory panel imports the remember/saveDoc
actions). On a cold start with a brand-new model the chat was paying
for all four at first paint.

Convert each import to React.lazy() with a Suspense boundary. Each
panel's JS chunk is fetched on first render (the first time the user
clicks the corresponding topbar chip), so the initial bundle loses
those four trees and any of their imports.

The fallback is null because the panels themselves are modal drawers
with their own loading state; a Suspense spinner would be a second
spinner stacked on top of whatever the panel renders.

The .then(m => ({ default: m.X })) adapter handles modules whose
named export is the public surface (every component file in this
repo, per CodeViewer's 'editor seam' pattern).
@esengine

esengine commented Jun 6, 2026

Copy link
Copy Markdown
Owner

Thanks! This conflicts with the latest main-v2 in App.tsx. Could you rebase onto the latest main-v2? Several of your desktop PRs touch App.tsx (#3126, #2948) and useController.ts (#3114, #2948) — rebasing them as one ordered chain avoids repeated conflicts. Happy to merge once green. Thank you!

@esengine

esengine commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Nice perf win — code-splitting these panels is worth doing. Could you rebase on the latest main-v2? It drifted under this PR: HistoryPanel and SettingsPanel changed props (trash support — kind/onRestore/onPurge, and initialTab/settingsTarget), and a new ContextPanel landed. Re-applying the React.lazy/Suspense wrapping on top of the new component calls (and deciding whether to lazy-load ContextPanel too) is cleaner from your side than a hand-merge from mine. Once rebased I'll get it in.

@esengine

Copy link
Copy Markdown
Owner

Covering the whole series (#3116, #3120, #3125, #3126, #3127, #2948) in one note: all six branches now conflict with main-v2 after today's merge batch. They're each still wanted — the React.lazy code-split and the batch delete in particular. If you rebase them onto the latest main-v2 I'll approve fork CI and review as they come green. If any of them no longer applies after the recent status-bar/overview redesign (#3922 reworked that area — the per-turn usage pill in #3127 likely needs rethinking against the new grouped metrics), feel free to close those and keep the rest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Go rewrite (1.x) — main-v2 branch, active development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants