#!/usr/bin/env bash # Builds one wasm-bindgen crate for the browser and drops the JS glue and the # .wasm where a page serves them from. # # Usage: scripts/build-wasm.sh [crate out-dir out-name] # # With no arguments it builds crates/didbot-site-anim into site/public/wasm/ # as site-anim.js + site-anim_bg.wasm, which is what scripts/build-site.sh # calls it for: Astro's public/ passthrough copies that directory into dist/ # untouched, so nothing else has to know this ran. The three arguments name # another crate, output directory and output name, and are all given or none # are; scripts/build-dashboard-wasm.sh, scripts/build-policy-wasm.sh and # scripts/build-policy-anim-wasm.sh are the other callers. # # This is its own script because it is the one step needing a toolchain the # rest of the site build does not: the wasm32-unknown-unknown target and a # wasm-bindgen-cli whose version matches the wasm-bindgen crate dependency # exactly (the two talk a private ABI to each other; a mismatch fails loudly, # which is the whole reason the version is pinned rather than "whatever is # installed"). # # `cargo build --workspace` and `cargo test --workspace` never need this: the # wasm32 target is only touched here, on purpose (see # crates/didbot-site-anim/Cargo.toml's own comment on why the crate builds # fine natively without it). This script is the opt-in. set -euo pipefail cd "$(dirname "$0")/.." case "$#" in 0) crate="didbot-site-anim" out_dir="site/public/wasm" out_name="site-anim" ;; 3) crate="$1" out_dir="$2" out_name="$3" ;; *) echo "usage: $0 [crate out-dir out-name]" >&2 exit 2 ;; esac locked_version="$( awk ' /^name = "wasm-bindgen"$/ { want = 1; next } want && /^version = / { gsub(/"/, "", $3); print $3; exit } ' Cargo.lock )" if [ -z "$locked_version" ]; then echo "build-wasm: could not find wasm-bindgen's locked version in Cargo.lock" >&2 exit 1 fi if ! rustup target list --installed 2>/dev/null | grep -qx wasm32-unknown-unknown; then echo "build-wasm: the wasm32-unknown-unknown target is not installed." >&2 echo " Install it with: rustup target add wasm32-unknown-unknown" >&2 exit 1 fi if ! command -v wasm-bindgen >/dev/null 2>&1; then echo "build-wasm: wasm-bindgen-cli is not installed." >&2 echo " Install the version matching Cargo.lock ($locked_version) with:" >&2 echo " cargo install wasm-bindgen-cli --version $locked_version --locked" >&2 exit 1 fi installed_version="$(wasm-bindgen --version | awk '{print $2}')" if [ "$installed_version" != "$locked_version" ]; then echo "build-wasm: wasm-bindgen-cli $installed_version does not match Cargo.lock's wasm-bindgen $locked_version." >&2 echo " wasm-bindgen and wasm-bindgen-cli speak a private ABI and must match exactly. Reinstall with:" >&2 echo " cargo install wasm-bindgen-cli --version $locked_version --locked" >&2 exit 1 fi # Which profile each crate is worth building under, rather than an argument, so # that the two call sites that build `didbot-site-anim` cannot drift apart. # # `didbot-policy-check` is megabytes of policy engine a visitor waits on, and # the root Cargo.toml's `wasm-release` takes a third off it. `didbot-site-anim` # is a per-frame numeric loop, which that profile leaves the same size to within # a few dozen bytes while running its cellular automaton at roughly half the # rate, so it builds under `release`. case "$crate" in didbot-policy-check) profile="wasm-release" ;; *) profile="release" ;; esac echo "=== cargo build: $crate for wasm32-unknown-unknown ===" >&2 cargo build -p "$crate" --target wasm32-unknown-unknown --profile "$profile" wasm_in="${CARGO_TARGET_DIR:-target}/wasm32-unknown-unknown/$profile/${crate//-/_}.wasm" if [ ! -f "$wasm_in" ]; then echo "build-wasm: expected build output at $wasm_in, found nothing" >&2 exit 1 fi echo "=== wasm-bindgen: generating the JS glue in $out_dir ===" >&2 # Only this module's files: policy-site/public/wasm/ holds two modules. rm -f "$out_dir/$out_name.js" "$out_dir/$out_name.d.ts" \ "$out_dir/${out_name}_bg.wasm" "$out_dir/${out_name}_bg.wasm.d.ts" mkdir -p "$out_dir" wasm-bindgen --target web --out-dir "$out_dir" --out-name "$out_name" "$wasm_in" size_bytes="$(wc -c <"$out_dir/${out_name}_bg.wasm")" echo "build-wasm: done — $out_dir/${out_name}_bg.wasm is ${size_bytes} bytes" >&2