Skip to content

perf(frontend): keep editor/terminal stacks out of unrelated surfaces - #830

Merged
Neonforge98 merged 2 commits into
perf/frontend-bundle-and-leaksfrom
perf/heavy-component-leaks
Aug 17, 2026
Merged

perf(frontend): keep editor/terminal stacks out of unrelated surfaces#830
Neonforge98 merged 2 commits into
perf/frontend-bundle-and-leaksfrom
perf/heavy-component-leaks

Conversation

@Harry19081

Copy link
Copy Markdown
Member

Stacked on #829 (perf/frontend-bundle-and-leaks). Merge that first; this PR's diff is only the top commit.

Summary

Second frontend RAM pass: stop the CodeMirror / xterm / syntax-highlighter / chart stacks from being loaded by surfaces that never render them. Measured with a static import-graph walk per lazy chunk root (src/test/staticImportGraph.ts), before → after:

Surface (chunk root) Before: heavy packages statically reachable After
engines/ChatPanel/events/stream/agent-message (every chat message) xterm, CodeMirror + langs, sql-formatter, react-syntax-highlighter, highlight.js, recharts, @a2ui, framer-motion, mammoth, jszip (1 747 files) none
modules/MainApp/TeamInbox xterm, CodeMirror, sql-formatter, framer-motion none
modules/MainApp/Settings/SettingsSlot CodeMirror, sql-formatter none
modules/MainApp/AgentOrgs CodeMirror, sql-formatter none
modules/ProjectManager/{Projects,WorkItems,LinearProjects} xterm, CodeMirror, sql-formatter, framer-motion none
engines/Simulator/index xterm, CodeMirror, sql-formatter, framer-motion none
modules/WorkStation/shared/index.ts (barrel, ~80 importers) xterm, CodeMirror, framer-motion none

Production build: 565 → 583 chunks (new lazy boundaries), duplicated-module bytes 1.86 MB → 1.54 MB, total unchanged (code moves between chunks — the win is what a given surface loads into the heap).

Problem

  • modules/WorkStation/shared/index.ts re-exported three heavy edges: GitFileDiffSplit (unreferenced dead code → all of features/CodeMirror), the SidebarModules block (whose module evaluation registers the Terminal tab sidebar → engines/TerminalCore → xterm + addons), and QuickActionsPanel (framer-motion). ~80 files import that barrel, so every workstation, PM, inbox and settings surface — and the agent-message renderer via Chat/Communication — statically reached the editor and terminal stacks.
  • Several on-demand views were imported eagerly by their hosts: SimulatorMessages in agent-message (its siblings user-message/thinking already lazy it), the raw-transcript content in SessionRawTranscriptDialog (its sibling view already lazies it), A2UIRenderer (recharts/@a2ui) and ReactArtifactRunner (sucrase + embedded React runtime) inside CanvasPreviewSurface, SkillEditorPanel in Settings, CodeMirrorEditor inside MarkdownEditor, the canvas "source" tab viewer.
  • Editor-only consumers imported the features/CodeMirror barrel, which also carries Diff, ConflictEditor, SqlEditor + sql-formatter.

Solution

  • Remove the three heavy re-exports from the WorkStation shared barrel (with comments explaining why they must not come back); CodeEditor/index.tsx imports SidebarSlot from ../shared/SidebarModules — the same import that already carried the side-effect registrations, so tab-sidebar registration is unchanged. Delete the unreferenced GitFileDiffSplit.
  • React.lazy + Suspense fallback={null} at the on-demand render sites listed above (all follow existing precedents in the same files/siblings).
  • Deep-import @src/features/CodeMirror/Editor at the seven editor-only consumers.
  • New guard src/app/root/__tests__/featureBoundaries.test.ts: nine surfaces asserted free of the editor/terminal/highlighter/chart stacks; failure output prints the import chain.

Potential risks

  • Each lazied surface shows an empty pane for one local chunk load the first time it renders (simulator variant of an agent message, raw-transcript dialog, A2UI/React canvas kinds, skill editor, markdown edit tab, canvas source tab). Same trade the neighbouring code already makes; auto-dismiss/loading states are unaffected.
  • Tab-sidebar registrations now depend solely on CodeEditor/index.tsx importing ../shared/SidebarModules (previously the barrel evaluated it as a side effect for everyone). CodeEditor is the only host that resolves SidebarSlot, so this is intended, but a future host in another module must import SidebarModules too — noted in the barrel comment.
  • The boundary guard is regex-based (not a full resolver): it can miss exotic import forms, and it will fail on legitimate new heavy usage until the allow-list is updated with a reason.

Validation / Test plan

  • pnpm typecheck clean; eslint clean on touched files (pre-commit lint-staged passed).
  • Full pnpm test: 1110 files / 8720 tests green (includes the new boundary guard and the perf(frontend): break down the startup bundle and bound frontend leaks #829 guards).
  • Production build succeeds; chunk-duplication analysis above.
  • Manual: send/receive chat messages (chat + simulator variants), open the raw transcript dialog, view A2UI/HTML/React canvases, open Settings → Integrations → Skills editor and Policy rule wizard, Agent Orgs wizard, Canvas app source tab, Terminal/Source-Control/Benchmark tab sidebars in the code editor.

The WorkStation shared barrel (imported by ~80 files) re-exported three heavy edges — GitFileDiffSplit (dead code → all of CodeMirror), the SidebarModules block (evaluates the Terminal tab sidebar → xterm) and QuickActionsPanel (framer-motion) — so TeamInbox, ProjectManager, Settings, Simulator and even the agent-message renderer statically reached the editor and terminal stacks. Cut those re-exports (CodeEditor keeps its explicit SidebarModules import for the registrations), delete the unreferenced GitFileDiffSplit, and lazy-load the remaining on-demand users: agent-message SimulatorMessages (same pattern as user-message/thinking; drops its static reach from 1747 files incl. xterm/CodeMirror/react-syntax-highlighter/highlight.js/recharts/mammoth/jszip to none of them), SessionRawTranscriptDialog content, CanvasPreviewSurface A2UIRenderer/ReactArtifactRunner, SkillsCategoryView SkillEditorPanel, MarkdownEditor CodeMirrorEditor, CanvasApp source viewer. Editor-only consumers deep-import features/CodeMirror/Editor instead of the barrel. Guard: src/app/root/__tests__/featureBoundaries.test.ts asserts nine lazily loaded surfaces stay free of the editor/terminal/highlighter/chart stacks.

Pre-commit hook ran. Total eslint: 14, total circular: 0
Pre-commit hook ran. Total eslint: 0, total circular: 0
@Neonforge98
Neonforge98 merged commit 9e4d57b into perf/frontend-bundle-and-leaks Aug 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants