CodeNomad/scripts/desktop-server-resources.cjs
Shantur Rathore 3ccdd36ad8
Reduce App package sizes (#453)
## Summary
- Trim Electron app packaging to only include runtime shell assets and
remove unused workspace runtime dependencies.
- Copy server resources explicitly, filtering stale build artifacts and
pruning known non-runtime dependency files.
- Bundle only the Node executable instead of the full Node distribution.

## Validation
- Built macOS Electron artifacts with `npm run build:mac --workspace
@neuralnomads/codenomad-electron-app`.
- Ran packaged server CLI smoke test: `dist/bin.js --version` returned
`0.16.0`.
- Ran packaged dependency import smoke test for pruned runtime
dependencies.

## Size Impact
- macOS x64 zip: 161M
- macOS arm64 zip: 161M
- macOS arm64 app bundle: 435M
- Packaged server node_modules: 25M
2026-05-15 19:13:13 +01:00

212 lines
5.7 KiB
JavaScript

const fs = require("fs")
const path = require("path")
const excludedDistRoots = new Set(["codenomad-server", "opencode-config", "opencode-config-template", "opencode-config.js"])
function copyPackagedServerResources(options) {
const { serverRoot, serverDest, log = () => {} } = options
fs.rmSync(serverDest, { recursive: true, force: true })
fs.mkdirSync(serverDest, { recursive: true })
copyRequiredArtifact(serverRoot, serverDest, "package.json", log)
copyRequiredArtifact(serverRoot, serverDest, "public", log)
copyRequiredArtifact(serverRoot, serverDest, "node_modules", log)
copyServerDist(serverRoot, serverDest, log)
stripNodeModuleBins(path.join(serverDest, "node_modules"), log)
pruneKnownServerDependencies(path.join(serverDest, "node_modules"), log)
}
function copyRequiredArtifact(serverRoot, serverDest, name, log) {
const from = path.join(serverRoot, name)
const to = path.join(serverDest, name)
if (!fs.existsSync(from)) {
throw new Error(`Missing required server artifact: ${from}`)
}
fs.cpSync(from, to, { recursive: true, dereference: true })
log(`copied ${name}`)
}
function copyServerDist(serverRoot, serverDest, log) {
const from = path.join(serverRoot, "dist")
const to = path.join(serverDest, "dist")
if (!fs.existsSync(from)) {
throw new Error(`Missing required server artifact: ${from}`)
}
fs.cpSync(from, to, {
recursive: true,
dereference: true,
filter(source) {
const relative = path.relative(from, source)
if (!relative) return true
const [root] = relative.split(path.sep)
if (excludedDistRoots.has(root)) return false
return !/\.test\.js$/.test(path.basename(relative))
},
})
log("copied filtered dist")
}
function stripNodeModuleBins(root, log) {
if (!fs.existsSync(root)) return
const stack = [root]
let removed = 0
while (stack.length > 0) {
const current = stack.pop()
if (!current) break
let entries
try {
entries = fs.readdirSync(current, { withFileTypes: true })
} catch {
continue
}
for (const entry of entries) {
const full = path.join(current, entry.name)
if (entry.name === ".bin") {
fs.rmSync(full, { recursive: true, force: true })
removed += 1
continue
}
if (entry.isDirectory()) {
stack.push(full)
}
}
}
if (removed > 0) {
log(`removed ${removed} node_modules/.bin directories`)
}
}
function removeIfExists(target) {
if (!fs.existsSync(target)) return 0
fs.rmSync(target, { recursive: true, force: true })
return 1
}
function removeFilesMatching(root, patterns) {
if (!fs.existsSync(root)) return 0
const stack = [root]
let removed = 0
while (stack.length > 0) {
const current = stack.pop()
if (!current) break
let entries
try {
entries = fs.readdirSync(current, { withFileTypes: true })
} catch {
continue
}
for (const entry of entries) {
const full = path.join(current, entry.name)
if (entry.isDirectory()) {
stack.push(full)
continue
}
if (entry.isFile() && patterns.some((pattern) => pattern.test(entry.name))) {
fs.rmSync(full, { force: true })
removed += 1
}
}
}
return removed
}
function prunePackage(root, options) {
if (!fs.existsSync(root)) return 0
let removed = 0
for (const relativePath of options.remove ?? []) {
removed += removeIfExists(path.join(root, relativePath))
}
if (options.filePatterns?.length) {
removed += removeFilesMatching(root, options.filePatterns)
}
return removed
}
function pruneKnownServerDependencies(root, log) {
if (!fs.existsSync(root)) return
let removed = 0
const declarationAndMaps = [/\.d\.[cm]?ts$/, /\.map$/]
const packageDocs = [/\.md$/i, /\.markdown$/i]
removed += prunePackage(path.join(root, "openai"), {
remove: ["CHANGELOG.md", "README.md", "bin", "src"],
filePatterns: [...declarationAndMaps],
})
removed += prunePackage(path.join(root, "fastify"), {
remove: ["docs", "examples", "integration", "test", "types", "build", "fastify.d.ts"],
filePatterns: [...packageDocs],
})
removed += prunePackage(path.join(root, "@fastify", "cors"), {
remove: ["bench.js", "benchmark", "test", "types"],
filePatterns: [...packageDocs],
})
removed += prunePackage(path.join(root, "@fastify", "reply-from"), {
remove: ["examples", "test", "types"],
filePatterns: [...packageDocs],
})
removed += prunePackage(path.join(root, "@fastify", "static"), {
remove: ["example", "test", "types", "tsconfig.eslint.json"],
filePatterns: [...packageDocs],
})
removed += prunePackage(path.join(root, "pino"), {
remove: [
"benchmarks",
"browser.js",
"build",
"docs",
"docsify",
"examples",
"favicon-16x16.png",
"favicon-32x32.png",
"favicon.ico",
"index.html",
"pino-banner.png",
"pino-logo-hire.png",
"pino-tree.png",
"pino.d.ts",
"pretty-demo.png",
"test",
"tsconfig.json",
],
filePatterns: [...packageDocs],
})
removed += prunePackage(path.join(root, "undici"), {
remove: ["docs", "index.d.ts", "scripts", "types"],
filePatterns: [...packageDocs],
})
removed += prunePackage(path.join(root, "zod"), {
remove: ["README.md", "src"],
filePatterns: [...declarationAndMaps],
})
removed += prunePackage(path.join(root, "yaml"), {
remove: ["README.md", "bin.mjs", "browser"],
filePatterns: [...declarationAndMaps],
})
removed += prunePackage(path.join(root, "node-forge"), {
remove: ["README.md", "flash"],
})
if (removed > 0) {
log(`removed ${removed} known non-runtime files/directories from server dependencies`)
}
}
module.exports = {
copyPackagedServerResources,
}