# Mathew — the Lean editor server # # Builds lean4web (https://github.com/leanprover-community/lean4web) from its # upstream source and runs its production server: one port serves the editor # client and the Lean sessions, which is what the wiki frames at /lean. # # Lean4web runs a real Lean process per session, so upstream asks for a # dedicated server — this image carries the editor and Mathlib, the machine # carries the load. # # docker build -t mathew-lean ./lean # docker run -p 8080:8080 mathew-lean # → http://localhost:8080 # # The build is heavy by nature (Mathlib is fetched and its precompiled cache # unpacked), but multi-stage keeps the junk out of the pushed image: the # compilers, npm dev dependencies and caches stay in the builder, and the # final image is a slim runtime with exactly what a session needs — the node # server, the elan toolchain, the built client, and the project's Lean cache. # # To ship an image without Mathlib itself (~4GB instead of ~11GB), pass # `--build-arg BAKE_MATHLIB=false` and hold the cache in a volume instead: # the entrypoint fills a fresh volume once at first start. See # "Keeping Mathlib out of the image" in lean/README.md. # ---------- build ---------- FROM node:24-bookworm AS build # lake fetches dependencies over git/curl, drives clang to link, and elan # (Lean's toolchain manager) installs the toolchains each project pins RUN apt-get update && apt-get install -y --no-install-recommends \ bash curl git ca-certificates unzip rsync \ build-essential clang pkg-config libssl-dev \ && rm -rf /var/lib/apt/lists/* # elan, with no default toolchain — every project pins its own in its # lean-toolchain file, and elan installs that one when asked RUN curl -sSfL https://elan.lean-lang.org/elan-init.sh | bash -s -- -y --default-toolchain none ENV PATH="/root/.elan/bin:${PATH}" # cypress (a root dev dependency) pulls an ~800MB browser bundle on install — # nothing in this build runs browser tests, so skip it ENV CYPRESS_INSTALL_BINARY=0 # The lean4web source. Pass a tag or branch to pin a build: # docker build --build-arg LEAN4WEB_REF=v0.2.2 ./lean ARG LEAN4WEB_REF=main RUN git clone --depth 1 --branch "${LEAN4WEB_REF}" \ https://github.com/leanprover-community/lean4web.git /opt/lean4web # Ship only the MathlibDemo project: the wiki opens the default project, and # upstream's second demo ("Stable") pins its own toolchain — elan would carry # a second ~3GB one that no session ever uses. RUN rm -rf /opt/lean4web/Projects/Stable WORKDIR /opt/lean4web RUN npm install # Build the Lean projects under Projects/. For MathlibDemo this fetches # Mathlib and unpacks its precompiled cache — the slow part of the image. # With BAKE_MATHLIB=false that step is skipped and only the pinned toolchain # is installed: the project ships unbuilt, and the entrypoint fills it on a # first start (the intended pairing is a volume over the project's .lake). ARG BAKE_MATHLIB=true RUN if [ "${BAKE_MATHLIB}" = "true" ]; then \ npm run build:projects; \ else \ (cd Projects/MathlibDemo && lake --version > /dev/null); \ fi # Mathew's theme layer: the wiki's font, stylesheet, and theme handshake # join the client's public/ so they ship in the built bundle, and a sed # wires them into index.html (and renames the tab). The wiki opens the # frame as ?theme=light|dark and the editor opens matching the page # around it — lean/theme/mathew.css explains how the skin attaches. COPY theme/mathew.css theme/theme-init.js ./client/public/ COPY theme/fonts/. ./client/public/fonts/ RUN sed -i \ -e 's##\n \n #' \ -e 's#