How to Build and Test WebAssembly in CI
Automating the build and test process for WebAssembly (Wasm) ensures code reliability and accelerates development. This guide provides a straightforward, step-by-step walkthrough on how to set up a continuous integration (CI) pipeline to compile and validate Wasm code, using GitHub Actions as the example platform.
Step 1: Define the Toolchain
Before configuring the pipeline, identify the language and toolchain used to compile your code to WebAssembly. The setup requirements differ depending on your source language:
- Rust: Uses
wasm-packor thewasm32-unknown-unknowntarget. - C/C++: Uses the Emscripten SDK
(
emsdk). - Go: Uses the Go compiler with environmental flags
(
GOOS=js GOARCH=wasm).
This guide demonstrates a Rust-based Wasm workflow, as it is currently the most common configuration for web-based Wasm deployments.
Step 2: Create the CI Configuration File
Create a configuration file in your repository. For GitHub Actions,
create a file named .github/workflows/wasm-ci.yml.
name: WebAssembly CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-id: 20
- name: Build WebAssembly
run: wasm-pack build --target web
- name: Run Tests
run: wasm-pack test --headless --chromeStep 3: Configure the Environment
The runner requires specific dependencies to execute tests. Because Wasm code runs in a browser environment or a JavaScript runtime, your CI runner must have those environments installed.
- Node.js: Necessary for executing server-side Wasm tests and running package managers like npm or Yarn.
- Headless Browsers: Necessary if your Wasm tests
rely on browser APIs (DOM, fetch, etc.). The configuration above uses
Chrome in headless mode, which is pre-installed on standard
GitHub-hosted runners (
ubuntu-latest).
Step 4: Compile the WebAssembly Code
To compile the source code, invoke your languageās compiler target within the CI environment.
In the YAML configuration, this is achieved via:
wasm-pack build --target webThis command compiles the Rust code into a .wasm binary
and generates the corresponding JavaScript glue code required to load
the module in a web browser.
Step 5: Run Unit and Integration Tests
Wasm tests typically run in one of two environments:
- Node.js (Server-side): Fastest execution time; ideal for computational logic that does not require browser APIs.
- Headless Browsers (Client-side): Runs inside a virtualized browser (Chrome, Firefox, or Safari) to ensure compatibility with web platforms.
To execute tests in a headless browser during the CI run, use:
wasm-pack test --headless --chromeIf you are testing in a Node.js environment, run:
wasm-pack test --nodeStep 6: Cache Dependencies
To speed up subsequent CI runs, cache your build dependencies. For
Rust, caching the target/ directory and the Cargo registry
reduces execution times significantly.
Add the following step to your workflow file before the build step:
- name: Cache Cargo dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}