Great article, the example makes the point really clear.
It probably applies just as well to other languages by the way.
Two small notes after completing my read:
1. You're using `npm prune --omit=dev` after the build. It's probably fast enough, but I'm wondering if it wouldn't be worth it to install the dependencies in two steps: first `dependencies` in a first image, then in a second image, copy those and rerun `npm install` to also install the `devDependencies`.
You could then copy in the final image:
- The production dependencies from the `deps` image
- The built code from the `build` image
2. Also, it's probably a detail, but you're copying the entire app folder in the final image, maybe you could save some extra bytes by only copying the built artifacts (e.g. `dist/` in most setups).
1. That's interesting, I actually never thought about that. It could work in practice and could even be parallelised! It would just download some, or most, packages twice. I'll test that, thanks.
2. Indeed, it's easier when building a small repo but with a monorepos you need to be careful about copying the /dist at the right place + the package.json to not break runtime import. I think once again it's balance between what would be perfect and what we can live with.
This is some great advice, manage to reduce my deploy & build time by half, but most importantly, understand better what I'm doing. As a Docker casual user, most resources out there never take the time to break it down like that. I remember reading about using the same Docker image for local dev too, so you're ISO in both environments, but it requires some more steps to watch for changes. Any plans to write an article about that?
Thanks for the feedback,
I actually don't use Docker images locally (except for services), I never found it particularly easy to do especially with hot-reload, node_modules, etc.
I wish in 2023 we had the tools to have a unified local-prod environment but seems like it's not for today
I thought it was once again an article on how to build NodeJS docker image... there are already thousands of them, BUT this one seems complete, great job! I'm always restarting from scratch because it's missing some tricks, some are too simple (HelloWorld kinda Dockerfile which is far from real world production) but your final image is neat. Maybe it's missing some example with ARG which is usually painful.
I'm curious though, why do you need to install `devDependencies` and other crap?
unfortunately it's mandatory to install devdeps to build the source code (typescript, webpack, esbuild, etc.) I just wish there was a buildDeps to avoid this confusion
Two small notes after completing my read:
1. You're using `npm prune --omit=dev` after the build. It's probably fast enough, but I'm wondering if it wouldn't be worth it to install the dependencies in two steps: first `dependencies` in a first image, then in a second image, copy those and rerun `npm install` to also install the `devDependencies`. You could then copy in the final image:
2. Also, it's probably a detail, but you're copying the entire app folder in the final image, maybe you could save some extra bytes by only copying the built artifacts (e.g. `dist/` in most setups).