A module's recipe starts from this image and invokes the compiler out of it, so the compiler had to be here. The same image was also what every module ran in, so every running container on every machine carried a compiler it would never invoke: 23 of the 28 MB of libraries. An earlier attempt to prune the build tools produced a smaller image that nothing could be built on, and the comment defending their return made a workaround look like a decision. One recipe, because the two must agree about the operating system, the language version and the library, and two files drift.
51 lines
2.9 KiB
Docker
51 lines
2.9 KiB
Docker
# Two images from one recipe: the one modules are COMPILED in, and the one they RUN in.
|
|
#
|
|
# **They were the same image, and that was a mistake.** A module's recipe starts from this and
|
|
# invokes the compiler out of it, so the compiler had to be here — and because the same image was
|
|
# also what every module ran in, every running container on every machine carried a TypeScript
|
|
# compiler it would never invoke. 23 of the 28 MB of libraries were that compiler. It was defended
|
|
# in a comment, which made a workaround look like a decision: the earlier attempt to prune the build
|
|
# tools produced a smaller image that nothing could be built on, and the answer to that is two
|
|
# images rather than one image that is bad at both jobs.
|
|
#
|
|
# Kept in one recipe deliberately. They must agree about the operating system, the language version
|
|
# and the library, and two files drift. `build.artifacts` in module.json names a stage each.
|
|
|
|
# ---- toolchain: what a module is compiled in -------------------------------------------------
|
|
FROM node:22-bookworm-slim AS toolchain
|
|
# git, because a dependency named by a git URL is fetched by git and this image does not carry it.
|
|
# Only here: what it is needed for happens at build time, and an image that can clone is an image
|
|
# that can be made to clone.
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends git ca-certificates \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
WORKDIR /app
|
|
COPY package.json package-lock.json ./
|
|
# Development dependencies included: the compiler is one, and so is the toolkit's own.
|
|
RUN npm install --no-audit --no-fund
|
|
# **And then compile the toolkit, because npm did not.** It declares a `prepare` script, the hook a
|
|
# package manager is supposed to run after installing from git, and this one does not run it — so
|
|
# the package arrives as sources with every entry point pointing at a compiled directory that is not
|
|
# there. Done explicitly rather than relying on a hook firing, which would break the day it stopped.
|
|
RUN npm --prefix node_modules/@novox/mesh-sdk install --no-audit --no-fund \
|
|
&& npm --prefix node_modules/@novox/mesh-sdk run build \
|
|
&& npm --prefix node_modules/@novox/mesh-sdk prune --omit=dev
|
|
COPY tsconfig.json ./
|
|
COPY src ./src
|
|
RUN npm run build
|
|
|
|
# ---- what the running image needs, and nothing else -------------------------------------------
|
|
# Its own stage so the toolchain image keeps its build tools while the runtime image does not. The
|
|
# prune has to happen somewhere, and doing it in the toolchain stage would take the compiler out of
|
|
# the image whose whole purpose is to have one.
|
|
FROM toolchain AS lean
|
|
RUN npm prune --omit=dev
|
|
|
|
# ---- runtime: what a module runs in -----------------------------------------------------------
|
|
FROM node:22-bookworm-slim AS runtime
|
|
WORKDIR /app
|
|
COPY package.json ./
|
|
COPY --from=lean /app/node_modules ./node_modules
|
|
COPY --from=toolchain /app/dist ./dist
|
|
ENTRYPOINT ["node", "dist/main.js"]
|