From afa68853f0ff4775a665d359627bb597d1f8b290 Mon Sep 17 00:00:00 2001 From: Jalil Date: Fri, 13 Nov 2026 17:41:05 -0800 Subject: [PATCH] perf(desktop): leave unused dependency files out of the package The packaged app shipped every file its dependencies publish. A running app never loads their source maps, type declarations, TypeScript's compiler command and language server, or SQLite's C sources. Filter those from both the collected and the staged copy of node_modules, keep the one TypeScript file computer use imports, and make the after-pack check fail if any of them returns. Also leave the Swift helper's build cache out of packages built from a checkout that compiled it. A macOS arm64 package of this commit goes from 291.0 MB to 106.4 MB of app.asar plus app.asar.unpacked: 87.6 MB in every build, and 97.0 MB of Swift build cache that only local builds carried. Signed-off-by: Jalil --- apps/desktop/electron-builder.base.yml | 12 ++++++++++++ apps/desktop/scripts/electron-after-pack.cjs | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/apps/desktop/electron-builder.base.yml b/apps/desktop/electron-builder.base.yml index 3c9e1ee084..b9f25ab066 100644 --- a/apps/desktop/electron-builder.base.yml +++ b/apps/desktop/electron-builder.base.yml @@ -9,8 +9,20 @@ files: - package.json # The staged copy below is compiled JavaScript; leave the checkout's source out. - "!node_modules/@openwork/types/{src,tsconfig*.json,tsup.config.ts}" + # The Swift helper ships under helpers; its build cache is checkout-only. + - "!node_modules/@openwork/computer-use/native/.build" + # Only a debugger or a compiler reads these, and nothing here runs one. + # The staged copy below repeats each rule so it cannot bring them back. + - &noSourceMaps "!**/*.{js,cjs,mjs,ts,cts,mts}.map" + - &noTypeDeclarations "!**/*.d.{ts,cts,mts}" + # Computer use transpiles scripts with lib/typescript.js alone. The compiler + # command, language server and translated messages are never loaded. + - &noTypeScriptTools "!**/typescript/{bin,lib/!(typescript.js)}" + # SQLite loads its prebuilt binary; the C sources only compile one. + - "!**/better-sqlite3/{deps,src}" - from: .electron-runtime/node_modules to: node_modules + filter: ["**/*", *noSourceMaps, *noTypeDeclarations, *noTypeScriptTools] extraResources: - from: .electron-runtime/openwork-sentry.json to: openwork-sentry.json diff --git a/apps/desktop/scripts/electron-after-pack.cjs b/apps/desktop/scripts/electron-after-pack.cjs index 5b00271555..3f6830f6e5 100644 --- a/apps/desktop/scripts/electron-after-pack.cjs +++ b/apps/desktop/scripts/electron-after-pack.cjs @@ -99,6 +99,24 @@ function verifyRuntimeDependencies(context) { } } verifyCompiledTypes(appAsarPath, packagedFiles); + verifyUnusedDependencyFiles(packagedFiles); +} + +// The packaging filters leave out dependency files that only a debugger or a +// compiler reads. Fail the package if they return, or if the filters take the +// one TypeScript file computer use imports. +function verifyUnusedDependencyFiles(packagedFiles) { + const typescript = "/node_modules/typescript"; + if (packagedFiles.has(`${typescript}/package.json`) && !packagedFiles.has(`${typescript}/lib/typescript.js`)) { + throw new Error("Packaged TypeScript is missing lib/typescript.js, which computer use imports."); + } + const unused = [...packagedFiles].filter((entry) => + /\.[cm]?[jt]s\.map$|\.d\.[cm]?ts$/.test(entry) + || /\/typescript\/(?:bin|lib\/(?!typescript\.js$)[^/]+)(?:\/|$)/.test(entry) + || /\/better-sqlite3\/(?:deps|src)(?:\/|$)/.test(entry)); + if (unused.length > 0) { + throw new Error(`Packaged app.asar ships files the app never loads: ${unused.slice(0, 5).join(", ")}`); + } } // The app loads @openwork/types as plain Node, which refuses TypeScript under @@ -209,4 +227,5 @@ module.exports = afterPack; module.exports.default = afterPack; module.exports.normalizeAsarEntryPath = normalizeAsarEntryPath; module.exports.verifyCompiledTypes = verifyCompiledTypes; +module.exports.verifyUnusedDependencyFiles = verifyUnusedDependencyFiles; module.exports.canonicalizeSidecars = canonicalizeSidecars;