Bundle Without External Packages

Use esbuild with --bundle --minify.

The more dependencies and source files one has, the more impact bundling and minification will have.

esbuild only supports bundling to ESM if the code and all of its dependencies are ESM modules. Otherwise, it has to be bundled as CommonJS, and in that case top-level await is not supported.

Also, minified JavaScript makes debugging production issues harder.

Result

Image (MB) Layer Count node Binary (MB) node_modules (MB) Server (B)

Baseline

1710

22

116.0

20.0

2515

Previous

113

17

41.6

6.2

2003

Result

106

16

41.6

0

1287240

$ SOURCE_DATE_EPOCH=1 GITHUB_SHA="N/A" scripts/docker_build.sh -p linux/amd64 -t 010-alpine-esbuild -n
...

$ docker images de.sdavids/sdavids-node-docker-image-slimming:010-alpine-esbuild --format "{{.Repository}}\t{{.Tag}}\t{{.Size}}"
de.sdavids/sdavids-node-docker-image-slimming  010-alpine-esbuild   106MB

$ docker run --rm de.sdavids/sdavids-node-docker-image-slimming:010-alpine-esbuild du -hs /usr/bin/node
41.6M /usr/bin/node

$ docker run --rm de.sdavids/sdavids-node-docker-image-slimming:010-alpine-esbuild du -hs /node
1.2M /node

$ docker run --rm de.sdavids/sdavids-node-docker-image-slimming:010-alpine-esbuild stat -c "%s" /node/server.cjs
1287240

$ docker run --rm de.sdavids/sdavids-node-docker-image-slimming:010-alpine-esbuild ls -A /node
healthcheck.mjs
server.cjs
tmp

$ docker image history --format "table {{.Size}}\t{{.CreatedBy}}" de.sdavids/sdavids-node-docker-image-slimming:010-alpine-esbuild
SIZE      CREATED BY
0B        LABEL org.opencontainers.image.licenses=Apac…
0B        HEALTHCHECK &{["CMD-SHELL" "node /node/healt…
0B        CMD ["node" "server.cjs"]
0B        EXPOSE [3000/tcp]
0B        USER node:node
0B        ENV PORT=3000
0B        ENV NODE_ENV=production
1.3MB     COPY --chown=node:node /node/dist ./ # build…
4.1kB     WORKDIR /node
2.99MB    COPY --chown=node:node /usr/lib/libgcc_s.so.…
43.6MB    COPY --chown=node:node /usr/local/bin/node /…
0B        ENV TMPDIR=/node/tmp
1.45MB    RUN /bin/ash -eo pipefail -c echo "https://d…
0B        SHELL [/bin/ash -eo pipefail -c]
0B        CMD ["/bin/sh"]
9.11MB    ADD alpine-minirootfs-3.23.2-x86_64.tar.gz /…

$ printf 'Layer Count: %s\n' "$(docker history de.sdavids/sdavids-node-docker-image-slimming:010-alpine-esbuild | tail -n +2 | wc -l | tr -d ' ')"
Layer Count: 16