Skip to content

fix(cli, scanner): exclude source maps from pkg binaries#2383

Open
dividedmind wants to merge 2 commits into
mainfrom
claude/pkg-binary-size-investigation
Open

fix(cli, scanner): exclude source maps from pkg binaries#2383
dividedmind wants to merge 2 commits into
mainfrom
claude/pkg-binary-size-investigation

Conversation

@dividedmind

@dividedmind dividedmind commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

Investigated why the packaged appmap CLI binary is so large (~560 MiB uncompressed). Findings and a fix for the biggest, safest win, applied to both packages/cli and packages/scanner.

Investigation

Built packages/cli for node22-linux-x64 (uncompressed) and diffed a bare-Node-runtime pkg binary against it to isolate the app payload (~74 MiB is just the Node runtime; the rest, ~485 MiB, is our payload). Then instrumented pkg -d to get the full list of files it actually packs, and summed their on-disk sizes grouped by source package:

Source Packed size
built/html (bundled Vue/React viewer apps) 107 MiB
node_modules/mermaid (see follow-up below) 81 MiB
node_modules/js-tiktoken (tokenizer data) 21 MiB
node_modules/lucide-vue (icon set) 20 MiB
node_modules/elkjs (graph layout, mermaid dep) 15 MiB
node_modules/better-sqlite3 (native binary) 12 MiB
... ...

The single biggest recurring pattern: development source maps (.js.map/.css.map) were being packed everywhere — not just our own built/html esbuild output (~81 MiB of maps there alone, since esbuild's default sourcemap: true inlines full original source per module), but also inside third-party node_modules packages that ship dev sourcemaps in their published builds (e.g. lucide-vue ships ~13 MiB of maps across its cjs/umd/esm builds).

Source maps are only consumed by a browser's devtools when a developer opens the panel for one of the bundled Vue/React viewer apps (appmap.html, navie.html, sequenceDiagram.html, the query-ui). The CLI itself never reads them at runtime — confirmed no code under packages/cli/src references .map files.

Fix

@yao-pkg/pkg supports a top-level ignore config (glob patterns, matched with picomatch) that excludes matching files from everything it packs — both the explicit assets globs and anything pulled in via its own dependency walk. Added:

"ignore": ["**/*.map"]

This does not touch the esbuild config (esbuild.html.ts still generates maps in built/, so local/npm-installed debugging workflows are unaffected) — it only strips maps from what actually goes into the packed executable. Applied the same one-line fix to packages/scanner.

Results (Linux x64, uncompressed payload unless noted)

cli:

Before After Saved
Uncompressed (None) 559.6 MiB 410.0 MiB −149.6 MiB (−26.7%)
GZip 221.6 MiB 187.0 MiB −34.6 MiB (−15.6%)
Brotli 191.3 MiB 164.1 MiB −27.2 MiB (−14.2%)
Zstd (current default) 221.0 MiB 185.4 MiB −35.6 MiB (−16.1%)

scanner (no esbuild/HTML bundle step, so this is entirely maps shipped inside its node_modules dependency tree — smaller win, still free):

Before After Saved
Uncompressed (None) 111.0 MiB 105.4 MiB −5.7 MiB (−5.1%)

Verified --help (cli) and scan --help (scanner) run correctly on the rebuilt binaries; no runtime code path in either package's src reads .map files.

This is independent of and stacks with #2382 (Zstd → Brotli compression switch).

Follow-up not included in this PR

packages/navie pins mermaid: "^9" while @appland/components uses ^10.9.1, so yarn can't dedupe them — navie gets its own private node_modules/navie/node_modules/mermaid@9.4.3 install just to call mermaid.parse() for AI-generated diagram syntax validation (packages/navie/src/lib/mermaid-filter.ts). That's ~20 MiB of pure duplication (measured after the source-map fix above; the raw duplicate was ~58 MiB before stripping maps).

This was attempted and reverted: the runtime fix (bump to ^10.9.1, await mermaid's now-async parse(), unwrap Node's require(esm) default-export wrapping) works correctly under plain Node, but mermaid v10 is ESM-only and dynamically imports each diagram-type grammar at parse() call time — Jest's CJS module runner can't execute that, and fixing it broke packages/cli's entire test suite (163/163 suites) via a shared global setup file that transitively loads navie. The right long-term fix is an ESM migration of packages/navie (or dual-building it like packages/models already does via tsup); revisit the mermaid dedup then.

Test plan

  • CI native builds succeed for all platforms
  • appmap --help, the bundled HTML viewers (appmap open, appmap query ui), and appmap-scanner scan --help still work correctly on built binaries
  • Binary size drop confirmed in CI artifact sizes

Source maps (.js.map/.css.map) are only useful for browser devtools
debugging of the bundled Vue/React viewer apps served from built/html;
the CLI never reads them at runtime. They were also being pulled in
wholesale from node_modules dependencies that ship dev sourcemaps in
their published packages (e.g. lucide-vue ships ~13 MiB of maps across
its cjs/umd/esm builds).

Measured on Linux x64: excluding **/*.map via pkg's ignore config drops
the uncompressed binary from 559.6 MiB to 410.0 MiB (-26.7%), verified
with `--help` still working correctly.
@dividedmind
dividedmind force-pushed the claude/pkg-binary-size-investigation branch from 5873448 to b4f258a Compare July 21, 2026 15:49
Same fix as the cli binary (previous commit): source maps are only
useful for debugging in a browser/devtools, never read by the CLI at
runtime, and get pulled in wholesale from node_modules dependencies
that ship dev sourcemaps in their published builds.

Scanner has no esbuild/HTML bundle step and doesn't set sourceMap in
its own tsconfig, so this is entirely maps shipped inside its
node_modules dependency tree. Smaller win than cli's (no large bundled
UI to strip maps from) but free and zero-risk:

Measured on Linux x64, uncompressed: 111.0 MiB -> 105.4 MiB (-5.1%).
Verified `scan --help` still works on the rebuilt binary.
@dividedmind dividedmind changed the title fix(cli): exclude source maps from pkg binary (-27% size) fix(cli, scanner): exclude source maps from pkg binaries Jul 22, 2026
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