Files
mesh-tools/Dockerfile
T
jschoubben 90a15cde20 The runtime keeps the compiler, because it is also the build environment
Every module's recipe starts from this image and invokes the compiler out of
it. Pruning build dependencies made a smaller image that nothing could be
built on.
2026-09-13 02:45:16 +02:00

58 lines
3.7 KiB
Docker

# The tool runtime: the base every module written in this toolchain is compiled on top of, and the
# container a node runs to serve them. It is handed the broker credential and the assigned modules'
# entrypoints at deploy time and serves them.
#
# **Built from this repository alone.** It used to copy in a compiled output directory that is not
# in source control, and resolve the mesh's own toolkit to a sibling checkout on the same disk — so
# it could only be produced on a workstation with two repositories laid out side by side, and its
# fingerprint was then typed into every module's recipe by hand. That put the one artifact the whole
# toolchain stands on outside the toolchain: nothing could rebuild it, so nothing could check it,
# and the rule that catches a base moving had no version on the far end of its edge and could never
# fire (novox/hq issue 044).
#
# Debian rather than Alpine, and root rather than an unprivileged user, because that is what the
# image actually in service is — and modules have already been built against it, one of which
# installs a package with Debian's package manager. This recipe said Alpine while serving Debian for
# as long as nobody could rebuild it to notice. Changing the operating system under every module is
# a separate decision from making this buildable, and is not being taken here.
FROM node:22-bookworm-slim AS build
# git, because a dependency named by a git URL is fetched by git and this image does not carry it.
# Only in the build stage: what it is needed for happens here, and a runtime that can clone is a
# runtime 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 of them, and so is the toolkit's own — it
# builds itself on install, which is what lets it be named by a git URL rather than fetched from a
# package registry this mesh does not yet run.
RUN npm install --no-audit --no-fund
# **And then compile the toolkit, because npm did not.** It declares a `prepare` script, which is
# the hook npm is supposed to run after installing a package from git — and this npm does not run
# it, so the package arrives as sources with every one of its entry points pointing at a compiled
# directory that is not there. The compile is therefore done here, explicitly: install the toolkit's
# own build dependencies inside it, build it, then drop them again so they do not travel into the
# image. Doing it by hand rather than relying on the hook is also the honest arrangement — a build
# that silently depended on a hook firing would break the day it stopped, in the same invisible way.
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
# Everything the modules compile against and run on.
#
# **The build dependencies stay, and that is deliberate.** This image is not only what a module runs
# in — it is also what every module is *compiled* in: a module's recipe starts from this and invokes
# the compiler out of these same directories. Dropping them would halve the image and break every
# module that builds on it, which is the sort of tidy-looking change that only fails somewhere else.
# If the two roles are ever separated, they should be separated deliberately and named separately.
FROM node:22-bookworm-slim
WORKDIR /app
COPY package.json ./
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
ENTRYPOINT ["node", "dist/main.js"]