From 2a76fb8ea303c72a527d39a3c70569a03b14da26 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 15 Oct 2026 17:28:25 +0000 Subject: [PATCH] perf(build): bundle dist with esbuild so installs fetch only native dependencies dist/ was one file per module plus nine runtime dependencies (47 packages, 38 MB on disk), and a cold `npx @kodycodes/cli` spent most of its 2.5 s downloading them. esbuild now bundles bin.ts and cli.ts with code splitting, so each `await import()` stays its own chunk and a command loads only what it uses, while every pure-JS dependency (MCP SDK, zod, add-mcp, inquirer, chokidar, es-module-lexer, trace-mapping) is compiled in. Only esbuild, @napi-rs/keyring and ps-list, which ship native code or platform binaries, remain dependencies. tsc still emits the declarations behind the package's `exports`. Co-Authored-By: bot_apk --- package.json | 14 +++++++------- scripts/build.mjs | 38 ++++++++++++++++++++++++++++++++++++++ tsconfig.build.json | 6 +++--- 3 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 scripts/build.mjs diff --git a/package.json b/package.json index c3c579f..fbe960c 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "skills" ], "scripts": { - "build": "tsc -p tsconfig.build.json", + "build": "node scripts/build.mjs && tsc -p tsconfig.build.json", "bench": "node scripts/bench.mjs", "typecheck": "tsc --noEmit", "test": "tsx --test test/*.test.ts", @@ -48,18 +48,18 @@ "access": "public" }, "dependencies": { - "@inquirer/checkbox": "^5.2.2", - "@jridgewell/trace-mapping": "^0.3.31", - "@modelcontextprotocol/client": "2.0.0", "@napi-rs/keyring": "^2.1.0", - "add-mcp": "^2.4.0", - "chokidar": "^4.0.3", - "es-module-lexer": "^3.0.3", "esbuild": "^0.25.12", "ps-list": "^9.0.0" }, "devDependencies": { + "@inquirer/checkbox": "^5.2.2", + "@jridgewell/trace-mapping": "^0.3.31", + "@modelcontextprotocol/client": "2.0.0", "@types/node": "^24.5.2", + "add-mcp": "^2.4.0", + "chokidar": "^4.0.3", + "es-module-lexer": "^3.0.3", "msw": "3.0.3", "tsx": "^4.20.5", "typescript": "^5.9.2" diff --git a/scripts/build.mjs b/scripts/build.mjs new file mode 100644 index 0000000..7315311 --- /dev/null +++ b/scripts/build.mjs @@ -0,0 +1,38 @@ +#!/usr/bin/env node +// Builds dist/ as an esbuild bundle instead of one file per module. +// +// Every pure-JS dependency is bundled, so `npm install @kodycodes/cli` only +// has to fetch the packages that ship native code or platform binaries (the +// `dependencies` in package.json): fewer tarballs and a fraction of the bytes, +// which is most of what a cold `npx @kodycodes/cli` waits on. Code splitting +// keeps every `await import()` in src a separate chunk, so a command still +// loads only what it uses. `kody:*` is resolved by workerd at run time and msw +// is installed into the Kody cache on demand, so both stay unbundled. +// +// CommonJS dependencies call `require()` for Node builtins; an ESM bundle has +// no `require`, so each output file gets one from `createRequire`. +import { rmSync } from 'node:fs' +import { createRequire } from 'node:module' +import { build } from 'esbuild' + +const pkg = createRequire(import.meta.url)('../package.json') + +rmSync('dist', { recursive: true, force: true }) + +await build({ + entryPoints: ['src/bin.ts', 'src/cli.ts'], + outdir: 'dist', + bundle: true, + splitting: true, + format: 'esm', + platform: 'node', + target: 'node22', + mainFields: ['module', 'main'], + external: [...Object.keys(pkg.dependencies), 'msw', 'kody:*'], + banner: { + js: "import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);", + }, + sourcemap: true, + sourcesContent: false, + logLevel: 'warning', +}) diff --git a/tsconfig.build.json b/tsconfig.build.json index 0ba2de0..2055810 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -2,10 +2,10 @@ "extends": "./tsconfig.json", "compilerOptions": { "noEmit": false, - "outDir": "dist", - "rootDir": "src", + "emitDeclarationOnly": true, "declaration": true, - "sourceMap": true + "outDir": "dist", + "rootDir": "src" }, "include": ["src/**/*.ts"] }