mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 09:41:04 +01:00
The production stage copied the entire build stage `/app` wholesale, including every workspace member's devDependencies (typescript, vite, vitest, storybook, rolldown, ...) and unrelated workspace members' own dependencies (ui's client-side bundle deps like mermaid, lucide-react), none of which the running server touches. That alone accounted for ~1.5GB of the shipped image. Add a `pruned-app` stage, forked from `build` after all builds finish, that re-resolves node_modules with `pnpm install --prod --frozen-lockfile --filter='@paperclipai/server...'` -- server plus everything it actually depends on, transitively, production-only. `production` now copies from `pruned-app` instead of `build`. The prune has to live in its own stage rather than in `build` directly: `cloud-plugins` and `cloud-server-deps` (declared later in the file) both fork from `build` and still need its full devDependency toolchain (typescript, etc.) to compile their own TypeScript at image build time. Move `tsx` from server's devDependencies to dependencies. It looked like a dev tool, but the image's own ENTRYPOINT imports it directly (`--import ./server/node_modules/tsx/...`) to transpile the workspace packages the server consumes by TypeScript source (their `exports` field points at `./src/*.ts`, not a prebuilt `dist`) -- it's genuinely required at runtime, and a naive prod-prune would have deleted it and broken every boot. Verified locally: the `cloud` target drops from 7.5GB to 5.53GB and the `production` target lands at 5.26GB. Boot-tested the built `cloud` image: embedded Postgres initializes, all migrations apply, `/api/health` returns 200, the UI serves, `@sentry/node` resolves to the version `server/package.json` declares, and tini/orphan-reaping passes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RD53WaVFqm8pbntKZ5seWy