Bundle With External Packages

Use esbuild with --bundle --minify --packages=external.

The more 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

1740

22

116.0

51.0

2515

Previous

117

17

41.3

10.9

2515

Result

117

17

41.3

10.9

2003

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

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

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

$ docker run --rm de.sdavids/sdavids-node-docker-image-slimming:009-alpine-esbuild-external du -hs /node
10.9M /node

$ docker run --rm de.sdavids/sdavids-node-docker-image-slimming:009-alpine-esbuild-external du -hs /node/node_modules
10.9M /node/node_modules

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

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

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

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

More Information