Repository navigation
Desktop artifacts ship the renderer's dependency tree twice #3146
Description
Problem
app.asar carries the raw sources of packages that exist only to be bundled into the renderer. Vite already emits everything the renderer loads into dist-renderer; the second copy in node_modules is never read.
Measured against main@794e760a9:
| Size | |
|---|---|
dist-renderer — what the renderer actually loads |
7.5 MB |
Same libraries again as raw node_modules inside app.asar |
~183 MB |
Largest contributors: mermaid 80 MB, lucide-react 30 MB, @astryxdesign 22 MB, @mermaid-js 12 MB, cytoscape-fcose 9 MB, react-dom 7 MB.
Why it happens
electron-builder.config.mjs declares files: ['dist/**/*', 'dist-renderer/**/*', 'package.json', ...], which does not mention node_modules. electron-builder then adds the full production dependency closure on its own. @maka/ui is a production dependency of @maka/desktop, and it pulls in mermaid, lucide-react, @astryxdesign/* and react, so all of them ship whole.
Nothing loads them at runtime:
dist/main/**anddist/preload/**contain norequire/importof@maka/ui,mermaid,lucide-react,react,react-dom,@astryxdesign/*,@xterm/xtermor@dnd-kit/*.- No main-process package depends on
@maka/ui. The single hit inpackages/core/dist/display-redaction.jsis a comment, not an import. dist-renderer/index.htmlreferences only relative./assets/*paths, so the bundle resolves nothing fromnode_modules.
One package needs care: @xterm/headless is required by packages/runtime and must keep shipping. Only @xterm/xterm and @xterm/addon-fit are renderer-side.
How it got here
Not any one change — three that were each reasonable alone:
| Date | Change | Effect |
|---|---|---|
| 07-26 | #1506 established the macOS release pipeline | production dependencies ship whole by default |
| 08-03 | #1929 added Mermaid rendering to Markdown | +80 MB, correctly code-split for the renderer |
| 08-05 | #2199 bundled a hermetic Git runtime | +151 MB (separate issue) |
Each author saw only their own slice, and CI has no artifact-size gate, so nothing reported the step changes.
Proposal
- Exclude the renderer-only tree from
filesin the electron-builder config, keeping@xterm/headless. - Add a packaged-size check to CI so a future step change is visible in the PR that causes it. Worth doing first — otherwise the reclaimed space returns in some other form within a couple of months.
Happy to take this one. Filing separately rather than folding it into a PR because the exclusion mechanism is a packaging-policy decision.
Not included here
The bundled Git runtime is a larger and separate finding: of its 151 MB, ~78 MB is a .NET runtime and ~17 MB is a 2D graphics library, both belonging to Git Credential Manager, which Maka does not use — it keeps credentials in its own credentials.json. A further ~13 MB comes from the 27 git builtins having lost their hardlinks (414 files, 415 inodes). I will file that separately if it is wanted.
Activity
build(desktop): stop shipping the renderer's dependency tree twice
Joob1n commentedon Aug 24, 2026
Claiming this one.
The baseline in the body is from
794e760a9and has moved twice since: #3457 removed the bundled Git runtime entirely, and the renderer-only tree has grown. Current sizes onmain:dist-renderer— what the renderer loadsmermaidlucide-react@astryxdesign@mermaid-jscytoscape-fcosereact-domThe diagnosis still holds:
filesinapps/desktop/electron-builder.config.mjsnamesdist/**/*,dist-renderer/**/*andpackage.jsonbut nothing aboutnode_modules, so electron-builder adds the production closure on its own.First step, because it decides the shape of the rest: establish what the packaged app actually reads at runtime, from the artifact rather than from the dependency graph. The body's exclusion list is derived from what imports what in
dist/mainanddist/preload, which is the right reasoning but not the same as evidence. A package that is only reached through a dynamic import, a worker entry, or a native binding would not appear in that scan and would fail at runtime rather than at build time. I will produce that list against a realmac-arm64build before writing any exclusion.@xterm/headlessis the case the body already flags — required bypackages/runtime, while@xterm/xtermand@xterm/addon-fitare renderer-side — and it is the shape I expect more of.Then, in order:
files, keeping whatever step 1 proves is reached.scripts/verify-packaged-app.mjsso a renderer-only package reappearing in the archive fails the check. Without that this regresses the first time someone adds a production dependency to@maka/ui, which is exactly how it got here.The size gate the body asks for is #3146's natural companion but a larger argument (what threshold, measured where, failing whose build), so I would rather land the exclusion plus the specific check first and open the gate separately unless a maintainer prefers otherwise.
sheng198298 commentedon Sep 8, 2026
take
drakeo338 commentedon Sep 17, 2026
Take
Astro-Han commentedon Sep 17, 2026
Fixed by #3148 (
22b79c5e1): thefileslist inapps/desktop/electron-builder.config.mjsnow excludesdist/renderer/**and the renderer-only dependency closure, so that tree no longer ships insideapp.asar.The packaged-size CI gate proposed as the second step is not implemented; it is a separate change and is worth filing as its own issue rather than keeping this one open.
drakeo338 commentedon Sep 17, 2026
feat(desktop): guard the packaged dependency closure with a reviewed …