perf(docker): install dependencies before copying source - #884
Conversation
`COPY . .` sat above `yarn install`, so any source edit invalidated that layer and everything below it. Every build therefore re-resolved and rebuilt the entire dependency tree from scratch -- twice, once for the compile and again for the production prune below the source copy. Copying only the manifests first confines dependency work to layers that change when package.json or yarn.lock change. The production tree also moves into its own stage rather than running as `rm -rf node_modules && yarn install --production` after the build: it depends solely on the manifests, so editing source no longer re-resolves it. That split is where most of the saving comes from. Measured on the same machine, both with warm caches, for a one-line source edit: 3m37s before, 14.5s after. `.yarnrc` is copied alongside the manifests. It carries `ignore-engines true`, which some transitive dependencies require to install at all; it was previously swept in by `COPY . .`, and copying the manifests without it fails the install outright. Deliberately uses no BuildKit-only features. A yarn cache mount would speed up dependency changes too, but the current Dockerfile builds under the legacy builder and adding `--mount=type=cache` would make BuildKit a hard requirement for anyone building locally. Verified this still builds with DOCKER_BUILDKIT=0. CI is unaffected either way -- it uses docker/setup-buildx-action. Output is unchanged: built from identical source, the original and restructured Dockerfiles produce a byte-identical compiled dist (721e6960bb4659a7, 469 files) and an identical runtime dependency tree (04d87018b84258a5, 1010 packages). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015R5EBQvBycT5dbNq2YRAgJ
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review. 📝 WalkthroughWalkthroughThe Dockerfile now separates cached dependency installation, production dependency installation, application compilation, and runtime packaging into distinct stages. ChangesDocker build pipeline
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to This change reorganizes Docker dependency and build stages to improve caching while retaining the production runtime dependency handoff. No concrete merge-blocking risk remains. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #884 +/- ##
===========================================
- Coverage 80.70% 80.69% -0.02%
===========================================
Files 143 143
Lines 57785 57785
Branches 4496 4495 -1
===========================================
- Hits 46634 46627 -7
- Misses 11096 11103 +7
Partials 55 55 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
A one-line source edit currently costs a full dependency reinstall — twice.
COPY . .sits aboveyarn install, so any source change invalidates that layer and everything below it. The build then re-resolves the whole tree for the compile, and again for the production prune that runs after the source copy.Measured
Same machine, both with warm caches, identical one-line source edit:
Most of the saving comes from moving the production install into its own stage. It depends only on the manifests, so editing source no longer re-resolves it — previously it ran as
rm -rf node_modules && yarn install --productionbelow the source copy and was rebuilt every time.Output is unchanged
Built from identical source, both Dockerfiles produce:
721e6960bb4659a7, 469 files — byte-identicalnode_modules:04d87018b84258a5, 1010 packages — identicalNo new requirements
Deliberately avoids BuildKit-only features. A yarn cache mount would also speed up genuine dependency changes, but the Dockerfile currently builds under the legacy builder and
--mount=type=cachewould make BuildKit a hard requirement for anyone building locally. Verified this still builds withDOCKER_BUILDKIT=0. CI is unaffected either way — it usesdocker/setup-buildx-action.One trap worth knowing
.yarnrchas to be copied alongside the manifests. It carriesignore-engines true, which some transitive dependencies need to install at all (@permaweb/aoconnectdeclares"engines": {"yarn": "please-use-npm"}). It was previously swept in byCOPY . .; copying the manifests without it fails the install outright. That cost me one build to discover.🤖 Generated with Claude Code
https://claude.ai/code/session_015R5EBQvBycT5dbNq2YRAgJ