jobs:
build:
runs-on: ubuntu-latest
container:
image: ghcr.io/discere-os/wasm-builder:latest
steps:
- uses: actions/checkout@v4
- name: Build WASM with Deno
run: deno task build:wasm
- name: Run tests
run: deno task testBefore (multiple setup steps, ~2-3 minutes):
steps:
- uses: actions/checkout@v4
- name: Setup Deno
uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- name: Setup Emscripten
uses: mymindstorm/setup-emsdk@v14
with:
version: 4.0.14
- name: Install Meson and Ninja
run: |
sudo apt-get update
sudo apt-get install -y meson ninja-build pkg-config
- name: Build WASM
run: deno task build:wasmAfter (single container, ~30 seconds):
steps:
- uses: actions/checkout@v4
- name: Build WASM
uses: docker://ghcr.io/discere-os/wasm-builder:latest
with:
args: deno task build:wasm# Navigate to zlib.wasm directory
cd client/emscripten/zlib.wasm
# Build using Docker (SIDE_MODULE - no dependencies)
docker run --rm \
-v $(pwd):/workspace \
-w /workspace \
ghcr.io/discere-os/wasm-builder:latest \
bash -c "deno task build:wasm"# libpng depends on zlib - must build both
cd client/emscripten
# Build dependency first
docker run --rm \
-v $(pwd)/zlib.wasm:/workspace \
-w /workspace \
ghcr.io/discere-os/wasm-builder:latest \
bash -c "./build-dual.sh side"
# Build libpng with dependency
docker run --rm \
-v $(pwd)/zlib.wasm:/workspace/zlib.wasm \
-v $(pwd)/libpng.wasm:/workspace/libpng.wasm \
-w /workspace/libpng.wasm \
ghcr.io/discere-os/wasm-builder:latest \
bash -c "deno task build:wasm"
# Meson finds zlib via PKG_CONFIG_PATH="../zlib.wasm/install/lib/pkgconfig"# Navigate to any Meson-based project (e.g., glib.wasm)
cd client/emscripten/glib.wasm
# Build using Docker
docker run --rm \
-v $(pwd):/workspace \
-w /workspace \
ghcr.io/discere-os/wasm-builder:latest \
bash -c "meson setup build --cross-file=emscripten-cross.ini && ninja -C build"# Start an interactive shell in the build environment
docker run --rm -it \
-v $(pwd):/workspace \
-w /workspace \
ghcr.io/discere-os/wasm-builder:latest \
bash
# Now you can run any build commands:
# emcc main.c -o main.js
# deno task build:wasm
# meson setup build && ninja -C buildname: CI/CD Pipeline
on:
push:
branches: [ wasm ]
pull_request:
branches: [ wasm ]
jobs:
test:
name: Test Suite (Deno)
runs-on: ubuntu-latest
container:
image: ghcr.io/discere-os/wasm-builder:latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Type check
run: deno check src/lib/index.ts
- name: Build WASM modules
run: deno task build:wasm
- name: Run tests
run: deno task test
- name: Run benchmarks
run: deno task bench
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: wasm-modules
path: install/wasm/- Setup time: 2-3 minutes
- Deno setup: ~30s
- Emscripten setup: ~90s
- System dependencies: ~30-60s
- Build time: Varies by project
- Total for small project: ~3-5 minutes
- Setup time: ~20-30 seconds (pull cached image)
- Build time: Same as traditional
- Total for small project: ~1-2 minutes
Savings: 2-3 minutes per build, 40-60% faster CI/CD
# Build multiple dependent libraries
for lib in zlib libpng freetype harfbuzz; do
docker run --rm \
-v $(pwd)/client/emscripten/$lib.wasm:/workspace \
-w /workspace \
ghcr.io/discere-os/wasm-builder:latest \
bash -c "deno task build:wasm"
doneIf you encounter permission errors with mounted volumes:
# Run as current user
docker run --rm \
--user $(id -u):$(id -g) \
-v $(pwd):/workspace \
-w /workspace \
ghcr.io/discere-os/wasm-builder:latest \
deno task build:wasm# Mount Emscripten cache directory
docker run --rm \
-v $(pwd):/workspace \
-v ~/.emscripten_cache:/emsdk/.emscripten_cache \
-w /workspace \
ghcr.io/discere-os/wasm-builder:latest \
deno task build:wasm- Push to GitHub:
cd toolchain/wasm-builder && git push - Trigger Build: GitHub Actions will automatically build and publish to GHCR
- Update Workflows: Replace setup steps in
client/emscripten/*/.github/workflows/with container usage - Test Locally: Run a local build with one of the WASM projects
After pushing, GitHub Actions will:
- Build the Docker image (~10-15 minutes first time)
- Run security scan with Trivy
- Publish to
ghcr.io/discere-os/wasm-builder:latest - Tag with git SHA and version
- Make available for all workflows