2026-06-18 21:00:25 +00:00
|
|
|
# syntax=docker/dockerfile:1
|
|
|
|
|
#
|
|
|
|
|
# Dockerfile.web-rust — container for the RUST web host (C1).
|
|
|
|
|
#
|
2026-07-02 16:08:17 +00:00
|
|
|
# Serves the Rust CanvasKit web editor: the `op-host-web-server` daemon running
|
2026-06-18 21:00:25 +00:00
|
|
|
# in `--serve-web` mode, hosting the wasm-bindgen bundle + the vendored
|
|
|
|
|
# CanvasKit artifact out of a `web-bundle/` directory placed next to the binary.
|
2026-07-02 16:08:17 +00:00
|
|
|
# This is the sole web container now that the TypeScript/Nitro web app (and its
|
|
|
|
|
# root `Dockerfile`) have been retired.
|
2026-06-18 21:00:25 +00:00
|
|
|
#
|
|
|
|
|
# Build (self-contained, builds the wasm bundle in-image — the default):
|
|
|
|
|
# docker build -f Dockerfile.web-rust -t openpencil-web-rust .
|
|
|
|
|
#
|
|
|
|
|
# Build reusing a prebuilt bundle (the `op-web-bundle` artifact from the
|
|
|
|
|
# `wasm-bundle-build.yml` CI job — skips the in-image wasm rebuild):
|
|
|
|
|
# # download + unzip the CI artifact into ./web-bundle first, then:
|
|
|
|
|
# docker build -f Dockerfile.web-rust --build-arg WEB_BUNDLE_SOURCE=copy \
|
|
|
|
|
# -t openpencil-web-rust .
|
|
|
|
|
#
|
|
|
|
|
# Run:
|
|
|
|
|
# docker run -p 3100:3100 openpencil-web-rust
|
|
|
|
|
# # then open http://localhost:3100/
|
|
|
|
|
#
|
|
|
|
|
# Why wasm-in-Docker is the default (vs. always COPY-artifact): the production
|
|
|
|
|
# `canvaskit` feature is pure Rust + web_sys + serde — it needs NO emscripten /
|
|
|
|
|
# EMSDK / skia-safe / libc shim (the from-scratch skia path that needed those
|
|
|
|
|
# was retired 2026-06-17; the editor renders through the official CanvasKit
|
|
|
|
|
# skia WASM loaded separately). So the only extra toolchain over a normal cargo
|
2026-07-08 14:43:09 +00:00
|
|
|
# build is the wasm32 target + wasm-bindgen-cli + pinned Binaryen (wasm-opt) +
|
|
|
|
|
# node, all installed in the builder stage. That keeps the image self-contained
|
|
|
|
|
# and reproducible. The `WEB_BUNDLE_SOURCE=copy` build arg is the
|
2026-06-18 21:00:25 +00:00
|
|
|
# fast path: it skips the wasm rebuild and copies a `./web-bundle` provided as
|
|
|
|
|
# build context (e.g. the Task-1 CI artifact).
|
|
|
|
|
|
|
|
|
|
# ── Stage 1: builder ──────────────────────────────────────────────────────────
|
2026-07-08 14:43:09 +00:00
|
|
|
# rust:1.94 ships cargo + a Debian (bookworm) base. Debian's apt binaryen is
|
|
|
|
|
# too old for rustc 1.94's wasm feature set, so wasm-opt is pinned below to the
|
|
|
|
|
# same modern Binaryen release used by the wasm bundle CI.
|
2026-06-18 21:00:25 +00:00
|
|
|
FROM rust:1.94-bookworm AS builder
|
|
|
|
|
|
|
|
|
|
# WEB_BUNDLE_SOURCE = build -> build the wasm bundle in this stage (default).
|
|
|
|
|
# = copy -> skip the build; the runtime stage COPYs a
|
|
|
|
|
# prebuilt ./web-bundle from the build context.
|
|
|
|
|
ARG WEB_BUNDLE_SOURCE=build
|
2026-07-08 14:43:09 +00:00
|
|
|
ARG BINARYEN_VERSION=version_123
|
2026-06-18 21:00:25 +00:00
|
|
|
|
|
|
|
|
# Port baked into the image's CMD; overridable at build + run time.
|
|
|
|
|
ARG SERVE_PORT=3100
|
|
|
|
|
|
2026-07-08 14:43:09 +00:00
|
|
|
# pinned Binaryen -> wasm-opt -Oz ; nodejs -> the 0-env-import assert in the gate
|
2026-06-19 14:35:22 +00:00
|
|
|
# script. op-host-web-server is the headless raster daemon (links op-host-services
|
2026-06-19 14:14:56 +00:00
|
|
|
# only — no winit/glutin/skia-GL under Approach Y), so NONE of the GL/X11
|
|
|
|
|
# link-time libs the desktop binary needed are required here; only
|
|
|
|
|
# freetype/fontconfig (+ CJK fonts) for skia's raster text shaping at export.
|
2026-06-18 21:00:25 +00:00
|
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
2026-07-08 14:43:09 +00:00
|
|
|
curl \
|
2026-06-18 21:00:25 +00:00
|
|
|
nodejs \
|
|
|
|
|
gzip \
|
|
|
|
|
ca-certificates \
|
|
|
|
|
pkg-config \
|
|
|
|
|
libfreetype-dev libfontconfig1-dev fonts-noto-cjk \
|
2026-07-08 14:43:09 +00:00
|
|
|
&& rm -rf /var/lib/apt/lists/* \
|
|
|
|
|
&& curl -fsSL \
|
|
|
|
|
"https://github.com/WebAssembly/binaryen/releases/download/${BINARYEN_VERSION}/binaryen-${BINARYEN_VERSION}-x86_64-linux.tar.gz" \
|
|
|
|
|
| tar -xz -C /opt \
|
|
|
|
|
&& ln -s "/opt/binaryen-${BINARYEN_VERSION}/bin/wasm-opt" /usr/local/bin/wasm-opt \
|
|
|
|
|
&& wasm-opt --version
|
2026-06-18 21:00:25 +00:00
|
|
|
|
|
|
|
|
WORKDIR /src
|
|
|
|
|
|
|
|
|
|
# Copy the whole repo (the `.dockerignore` trims node_modules / out / dist etc.)
|
|
|
|
|
# Submodules (vendor/jian) must already be checked out in the build context —
|
|
|
|
|
# the CI checkout uses `submodules: recursive`.
|
|
|
|
|
COPY . .
|
|
|
|
|
|
2026-06-19 14:14:56 +00:00
|
|
|
# Build the headless web/MCP server binary (the `--serve-web` host) — links
|
2026-06-19 14:35:22 +00:00
|
|
|
# op-host-services only, no winit/skia-GL. Always built; this is the runtime
|
2026-06-19 14:14:56 +00:00
|
|
|
# binary regardless of how the web bundle is produced.
|
|
|
|
|
RUN cargo build -p op-host-web-server --release
|
2026-06-18 21:00:25 +00:00
|
|
|
|
|
|
|
|
# Build the canvaskit wasm bundle in-image, UNLESS WEB_BUNDLE_SOURCE=copy.
|
|
|
|
|
# Mirrors `tools/check-wasm-bundle.sh` exactly (cargo build --features canvaskit
|
|
|
|
|
# -> wasm-bindgen --target web -> 0-env-import assert -> wasm-opt -Oz -> gzip
|
|
|
|
|
# size gate). The script reads the locked wasm-bindgen-cli version requirement
|
|
|
|
|
# from Cargo.lock so the CLI matches the linked runtime.
|
|
|
|
|
RUN if [ "$WEB_BUNDLE_SOURCE" = "build" ]; then \
|
|
|
|
|
rustup target add wasm32-unknown-unknown && \
|
2026-07-08 14:32:12 +00:00
|
|
|
version="$(awk '/^name = "wasm-bindgen"$/{found=1; next} found && /^version = /{gsub(/[" ]/,"",$3); print $3; exit}' Cargo.lock)" && \
|
|
|
|
|
if [ -z "$version" ]; then echo "could not resolve wasm-bindgen version from Cargo.lock" >&2; exit 2; fi && \
|
2026-06-18 21:00:25 +00:00
|
|
|
cargo install wasm-bindgen-cli --version "$version" --locked && \
|
|
|
|
|
bash tools/check-wasm-bundle.sh ; \
|
|
|
|
|
else \
|
|
|
|
|
echo "WEB_BUNDLE_SOURCE=$WEB_BUNDLE_SOURCE — skipping in-image wasm build; runtime stage will COPY ./web-bundle from the build context" ; \
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Assemble the deployable web-bundle/ layout the daemon's `web_static.rs`
|
|
|
|
|
# resolves: the wasm-bindgen `pkg/` output PLUS the vendored CanvasKit artifact
|
|
|
|
|
# under a `canvaskit/` subdir. For the `copy` path the bundle already exists in
|
|
|
|
|
# the build context (./web-bundle); just normalize it into /out/web-bundle so
|
|
|
|
|
# the runtime stage has one stable source path either way.
|
|
|
|
|
RUN mkdir -p /out/web-bundle && \
|
|
|
|
|
if [ "$WEB_BUNDLE_SOURCE" = "build" ]; then \
|
|
|
|
|
cp -R crates/op-host-web/pkg/. /out/web-bundle/ && \
|
|
|
|
|
cp -R crates/op-host-web/assets/canvaskit /out/web-bundle/canvaskit ; \
|
|
|
|
|
else \
|
|
|
|
|
cp -R web-bundle/. /out/web-bundle/ ; \
|
|
|
|
|
fi && \
|
|
|
|
|
echo "assembled web-bundle:" && find /out/web-bundle -maxdepth 2 -type f | sort
|
|
|
|
|
|
|
|
|
|
# ── Stage 2: runtime (slim) ───────────────────────────────────────────────────
|
|
|
|
|
# Only the runtime shared libs the daemon dlopens at run time (GL / fontconfig /
|
|
|
|
|
# freetype + CJK fonts). No Rust toolchain, no node, no build deps.
|
|
|
|
|
FROM debian:bookworm-slim AS runtime
|
|
|
|
|
|
|
|
|
|
ARG SERVE_PORT=3100
|
|
|
|
|
ENV OPENPENCIL_SERVE_PORT=${SERVE_PORT}
|
|
|
|
|
|
|
|
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
|
|
|
ca-certificates \
|
|
|
|
|
libfreetype6 libfontconfig1 fonts-noto-cjk \
|
|
|
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
|
|
|
|
|
|
WORKDIR /app
|
|
|
|
|
|
|
|
|
|
# Lay out the bundle the way `web_static.rs` expects: the daemon resolves the
|
|
|
|
|
# bundle as `<exe_dir>/web-bundle` (and CanvasKit as `<exe_dir>/web-bundle/
|
|
|
|
|
# canvaskit`). Keep the binary + the bundle dir as siblings under /app so that
|
|
|
|
|
# `<exe_dir> == /app`.
|
2026-06-19 14:14:56 +00:00
|
|
|
COPY --from=builder /src/target/release/op-host-web-server /app/op-host-web-server
|
2026-06-18 21:00:25 +00:00
|
|
|
COPY --from=builder /out/web-bundle /app/web-bundle
|
|
|
|
|
|
|
|
|
|
EXPOSE ${SERVE_PORT}
|
|
|
|
|
|
|
|
|
|
# Bind 0.0.0.0 so the daemon is reachable from outside the container (the LAN /
|
|
|
|
|
# Docker opt-in documented in `parse_serve_web_args`). No TLS — front with a
|
|
|
|
|
# reverse proxy for anything beyond a trusted network. The port is taken from
|
|
|
|
|
# the build-time SERVE_PORT (baked into OPENPENCIL_SERVE_PORT); `sh -c` lets the
|
|
|
|
|
# env var expand at container start.
|
2026-06-19 14:14:56 +00:00
|
|
|
CMD ["sh", "-c", "exec /app/op-host-web-server --serve-web \"${OPENPENCIL_SERVE_PORT}\" --host 0.0.0.0"]
|