# syntax=docker/dockerfile:1 ARG RUST_VERSION=1.98.1 # ---- Base: Rust toolchain + build tools ---- FROM rust:${RUST_VERSION}-slim-bookworm AS chef WORKDIR /app RUN apt-get update \ && apt-get install -y --no-install-recommends curl ca-certificates \ && rm -rf /var/lib/apt/lists/* # Install the toolchain declared in rust-toolchain.toml (incl. wasm32 target) in its own layer COPY rust-toolchain.toml . RUN rustup show active-toolchain || rustup toolchain install # Prebuilt binaries via cargo-binstall; wasm-bindgen-cli must match the version in Cargo.lock RUN curl -L --proto '=https' --tlsv1.2 -sSf \ https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash \ && cargo binstall -y --locked cargo-chef trunk # ---- Planner: compute the dependency recipe ---- FROM chef AS planner COPY . . RUN cargo chef prepare --recipe-path recipe.json # ---- Builder: cook deps (cached), then build the site with trunk ---- FROM chef AS builder COPY --from=planner /app/recipe.json recipe.json # Must match the flags trunk passes to cargo (see web/index.html) to reuse the cache RUN cargo chef cook --release --target wasm32-unknown-unknown --no-default-features \ --recipe-path recipe.json COPY . . RUN mkdir -p assets RUN --mount=type=cache,target=/root/.cache/trunk \ trunk build --release --locked # ---- Runtime: static files served by nginx ---- FROM nginx:1.29-alpine AS runtime COPY <<'EOF' /etc/nginx/conf.d/default.conf server { listen 3000; server_name _; root /usr/share/nginx/html; index index.html; gzip on; gzip_types application/wasm application/javascript text/css; # Bevy expects real 404s for missing assets (Trunk.toml: no_spa = true) location / { try_files $uri $uri/ =404; } location ~* \.(wasm|js|css)$ { add_header Cache-Control "public, max-age=31536000, immutable"; try_files $uri =404; } location = /index.html { add_header Cache-Control "no-cache"; } } EOF COPY --from=builder /app/dist /usr/share/nginx/html EXPOSE 3000