Skip to content

perf: re-enable code splitting in Desktop with vendor chunk grouping - #55181

Closed
Stoltemberg wants to merge 2 commits into
NousResearch:mainfrom
Stoltemberg:perf/desktop-code-splitting
Closed

perf: re-enable code splitting in Desktop with vendor chunk grouping#55181
Stoltemberg wants to merge 2 commits into
NousResearch:mainfrom
Stoltemberg:perf/desktop-code-splitting

Conversation

@Stoltemberg

@Stoltemberg Stoltemberg commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Re-enables Vite code splitting in the Desktop app (previously disabled due to Shiki causing OOM in electron-builder with thousands of dynamic chunks) by grouping heavy vendor libraries into dedicated chunks via manualChunks. This reduces the initial JS bundle from 27.6 MB to 2.3 MB (91.8% reduction).

Related Issue

Improves Desktop startup performance and memory usage. Related to #55191 (Desktop renderer crash-loops on large conversations) — smaller initial bundle reduces memory pressure.

Type of Change

  • ⚡ Performance improvement (non-breaking change that improves performance)

Changes Made

  • apps/desktop/vite.config.ts: Replace codeSplitting: false with manualChunks function that groups:
    • shiki-vendor: Shiki + react-shiki (~18.6 MB, lazy-loaded when viewing code)
    • mermaid-vendor: Mermaid (~3.9 MB, lazy-loaded when rendering diagrams)
    • codemirror-vendor: CodeMirror (~1.5 MB, lazy-loaded when editing code)
    • katex-vendor: KaTeX (~289 KB, lazy-loaded when rendering math)

How to Test

  1. Run cd apps/desktop && npm run build — should succeed with vendor chunks separated
  2. Verify chunk structure: ls -la dist/assets/*.js — should show index-*.js (~2.3 MB) plus vendor chunks
  3. Run npm run assert-dist-built — should pass
  4. Launch the desktop app and verify:
    • Initial load is faster
    • Code highlighting works (Shiki loads on demand)
    • Mermaid diagrams render (loads on demand)
    • Code editing works (CodeMirror loads on demand)

Performance

Metric Before After
Initial JS bundle 27.6 MB 2.3 MB
shiki-vendor (inline) 18.6 MB (lazy)
mermaid-vendor (inline) 3.9 MB (lazy)
codemirror-vendor (inline) 1.5 MB (lazy)
katex-vendor (inline) 289 KB (lazy)

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run npm run build in apps/desktop and it succeeds
  • I've run npm run assert-dist-built and it passes
  • I've tested on my platform: Windows

Documentation & Housekeeping

  • I've updated relevant documentation — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — Vite config is platform-agnostic
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Re-enable Vite code splitting (previously disabled due to Shiki OOM
issues with electron-builder) by grouping heavy vendor libraries into
dedicated chunks via manualChunks:

- shiki-vendor: Shiki + react-shiki (~18.6 MB)
- mermaid-vendor: Mermaid (~3.9 MB)
- codemirror-vendor: CodeMirror (~1.5 MB)
- katex-vendor: KaTeX (~289 KB)

This reduces the initial JS bundle from 27.6 MB to 2.3 MB (91.8%).
Heavy chunks load on demand when their features are used.
@alt-glitch alt-glitch added type/perf Performance improvement or optimization comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have labels Jun 29, 2026
CodeMirror is only needed when the user opens a file for editing.
Use React.lazy() + Suspense to defer loading the CodeEditor component
until it's actually rendered, reducing initial page load.

With code splitting enabled, this creates a separate chunk that loads
on demand instead of blocking the initial render.

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Clean 2-file performance fix re-enabling code splitting in Desktop with vendor chunk grouping. Reduces initial bundle load time. Well-scoped webpack config change.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for targeting the Desktop startup bundle. The premise remains active: current main deliberately disables splitting in apps/desktop/vite.config.ts:45-55 because Shiki's dynamic output previously caused electron-builder OOMs.

Problems

  • apps/desktop/vite.config.ts:29 groups modules into vendor assets, but it does not make static imports lazy. Startup statically reaches Shiki and KaTeX through apps/desktop/src/app/desktop-controller.tsx:78, apps/desktop/src/app/chat/index.tsx:13, and apps/desktop/src/components/assistant-ui/markdown-text.tsx:24-27. It also reaches CodeMirror through apps/desktop/src/app/desktop-controller.tsx:87, apps/desktop/src/app/chat/sidebar/index.tsx:105, apps/desktop/src/app/chat/sidebar/profile-switcher.tsx:25, and apps/desktop/src/components/chat/code-editor.tsx:1-5. The right-rail-only LazyCodeEditor cannot make that dependency on-demand.
  • The existing build guard only requires one emitted JS asset (apps/desktop/scripts/assert-dist-built.mjs:35-46), so it does not protect the packaging/chunk-cardinality constraint that led to codeSplitting: false.

Suggested changes

  • Move every startup-reachable heavy import behind a real lazy boundary, or limit the claim to output grouping rather than initial-load reduction.
  • Add an invariant-oriented build/packaging regression check and validate the real packaging path.

Automated hermes-sweeper review.

codeSplitting: false
}
}
manualChunks(id) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

manualChunks only groups modules; it does not defer modules that are statically reachable at startup. Main still statically reaches Shiki/KaTeX via the chat transcript and CodeMirror via ChatSidebarProfileRail, so these vendor chunks remain initial dependencies. Please establish lazy boundaries for those paths (or narrow the performance claim) before re-enabling splitting.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 2026

@GottZ GottZ left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was generated by AI during triage.

Summary

Three PRs are associated with this complex, but they address distinct Desktop causes: #40735 fixes worktree font serving, #55181 changes renderer chunking to reduce the startup bundle, and #64685 addresses Windows dependency resolution plus remote-display GPU fallback.

Related pull requests

  • #40735 [closed] related — (+26/-1) — implemented independently: the diff whitelists realpath-resolved node_modules directories so Vite can serve fonts from symlinked worktrees; it remains relevant as the reference implementation already landed on main and was folded into #69938.
  • #55181 related — (+27/-12) — keep open for substantial revision: manual vendor chunks change asset grouping but do not make the statically imported Shiki, KaTeX, and CodeMirror paths lazy, while the only new lazy boundary covers the right-rail CodeEditor; the diff also adds no guard for the chunk-cardinality constraint behind the prior electron-builder OOM. This agrees with the contributor keep_open review on #55181.
  • #64685 related — (+10/-1) — keep open, but not ready to merge: the fflate alias directly addresses the hoisted Windows workspace import, and the revised diff correctly avoids automatic --no-sandbox, but it still applies additional GPU switches to every remote-display reason and adds no requested platform-specific helper tests. This agrees with the contributor keep_open review on #64685 and must address its SSH/X11 scope concern.

Suggested consolidation

Keep #55181 as the candidate for the code-splitting work, but do not merge it as-is until actual lazy import boundaries and a packaging/chunk-cardinality regression guard address the documented OOM cause. #40735 is already implemented on main, and #64685 should remain a separate Windows/remote-display fix; neither is a duplicate of #55181, so no PR in this set should be closed as its duplicate.

Cross-PR triage: Reviewed 3 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 7 kB of PR diffs, 5 kB of issue/PR text, 4 kB of discussion (6 comments), 0 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

@Stoltemberg

Copy link
Copy Markdown
Contributor Author

Closing — the reviewer flagged that manualChunks only groups modules but does not defer statically-reachable imports. Main still reaches Shiki/KaTeX via chat transcripts and CodeMirror via ChatSidebar, so the chunks created here would still be loaded synchronously at startup. The premise of the PR is not met by the proposed change.

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

Labels

comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/perf Performance improvement or optimization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants