Payload slimming, pre-signing half: the asar stops shipping the world

The measured problem (330MB DMG / 1066MB app): electron-builder's
dependency collector packed the whole production dep tree into
app.asar (502MB) regardless of the files allow-list, because
normalizeFiles turns the array into one {filter} fileSet whose
entries ALL feed the per-dep copier (its implicit '**/*' passing
everything), and unpacked the native rungs into a 150MB
app.asar.unpacked. The launcher needs nothing but electron + node
builtins — the server ships via extraResources.

The fix (electron-builder.yml files): gitignore-style negation
ordering — '!**/*' first excludes everything, then only
electron/** and package.json re-include. The same list reaches the
per-dep filter, where app-builder-lib's destination-path quirk
(stat.moduleFullFilePath in util/filter.js) means no dep file can
ever re-include: all 566 modules collect zero files (DEBUG-mode
verified). Locale trim rides along (mac.electronLanguages: en).

Result on a fresh desktop:dist: app.asar 502MB -> 16KB (shell only:
electron/main.cjs, preload.cjs, package.json), app.asar.unpacked
gone, Frameworks 288MB -> 239MB, app 1066MB -> 367MB, DMG 330MB ->
144MB. Resources/server curation untouched (127MB, sharp native +
pdfjs traced and verified live).

Live verification against the packaged app: server spawn via
ELECTRON_RUN_AS_NODE on its kernel-assigned port, model slots via
PUT /api/settings/models, chat round-trip streaming an exact echo,
read tool on a PDF through the pdfjs path (exact text extracted),
image attach through the vision slot, GET /api/graph snapshot and
render-settings.

Docs full-accuracy pass (owner-approved scope): README +
docs/architecture.md swept of the dead embeddings / graph-context
injection / cluster-namer / semantic-clusters story (wave-7
casualties), MODELS/config roster rewritten to the BYOK slot
chain, EXTRACTION.chunkTokens -> graph.extractionChunkTokens,
route count 16 -> 25, steer_ctx_ dropped, seam table re-pointed at
the prober graph tools; docs/research/stt.md:50's "we already ship
transformers.js" premise corrected; config.ts orphaned EXTRACTION
doc block (left over from eed4b4e) deleted.

Note for master: npm prune still owed in the master tree (~690MB
stale @huggingface/onnxruntime trees absent from the lockfile);
worktree tree is clean and verified.
This commit is contained in:
amosblomqvist
2026-09-24 20:50:52 +03:00
parent 6896c23cc2
commit 085fdc1a98
5 changed files with 77 additions and 62 deletions
+30 -1
View File
@@ -14,7 +14,31 @@ productName: LearnHarness
directories:
output: dist
files:
# Only the shell goes into the asar.
# Only the shell goes into the asar. ORDER IS LOAD-BEARING (payload
# wave, 2026-09-24): electron-builder's dependency collector packs the
# whole production dep tree into node_modules/ REGARDLESS of this
# allow-list — normalizeFiles turns this array into one {filter: [...]}
# fileSet, getNodeModuleFileMatcher feeds EVERY filter entry (positives
# included) to the per-dep copier, and without a negation its implicit
# '**/*' passes everything (the measured result: a 502MB asar holding
# next/@ai-sdk/pdfjs/mermaid/puppeteer… while the launcher requires
# nothing but electron + node builtins — the server ships via
# extraResources).
#
# The fix is gitignore-style ordering (verified against the installed
# app-builder-lib 26.15.3 + a DEBUG-mode rebuild): '!**/*' first excludes
# EVERYTHING, the two positives after it re-include only the shell.
# The per-dep collector then contributes ZERO files — app-builder-lib's
# filter evaluates each dep file's DESTINATION path (the
# stat.moduleFullFilePath quirk in util/filter.js getRelativePath), so
# '!**/*' matches every 'node_modules/<dep>/...' path and the bare
# positives can never re-include one (DEBUG logs confirm filesCount=0
# for all 566 modules). If a future electron-builder fixes that quirk,
# ~1MB of package.json stubs would start landing — harmless. The
# two-package.json layout avoids the collector entirely but
# restructures the repo. app.asar.unpacked dies with it: the natives
# were only unpacked because their packages were packed.
- "!**/*"
- electron/**/*
- package.json
extraResources:
@@ -35,6 +59,11 @@ mac:
- target: dmg
arch:
- arm64
# Locale trim (payload wave, 2026-09-24): English-only app — cuts
# every non-en .lproj from the frameworks (the STT/mic entitlements
# don't depend on locales). Revisit only if localization ever lands.
electronLanguages:
- en
category: public.app-category.education
# Laid for the STT milestone (researcher-verified): the TCC mic prompt
# reads this string; macOS asks regardless of Electron's own handlers.