Living Document Notice
Published 2026-09-14. The evolving architecture, revisions, and connected notes for this dispatch live in the Stax Digital Garden.
Compiling the Engine to WebAssembly
Summary
Executing the Bosun parsing and graph engine directly inside browser runtimes requires cross-compiling the Rust codebase to the wasm32-unknown-unknown target. Relying on heavy runtime shims or POSIX emulation layers degrades startup performance and expands binary payloads.
The Bosun WebAssembly compilation pipeline strips standard library dependencies that depend on host operating system syscalls. By utilizing linear memory exchange buffers, link-time optimization, and targeted binary stripping, the compiled WASM engine runs in modern browser workers with minimal bundle weight.
Zero-Copy Linear Memory Exchange
Transferring multi-megabyte Markdown strings across JavaScript and WebAssembly boundaries often triggers duplicate string allocations. Bosun eliminates this memory duplication by mapping strings directly into WASM linear memory.
#[no_mangle]
pub extern "C" fn bosun_alloc(size: usize) -> *mut u8 {
let mut buffer = Vec::with_capacity(size);
let ptr = buffer.as_mut_ptr();
std::mem::forget(buffer);
ptr
}
#[no_mangle]
pub extern "C" fn bosun_parse_buffer(ptr: *const u8, len: usize) -> u32 {
let slice = unsafe { std::slice::from_raw_parts(ptr, len) };
let cst = parse_markdown_slice(slice);
cst.node_count() as u32
}The browser JavaScript client allocates space inside the WebAssembly instance memory buffer, writes UTF-8 bytes directly via TextEncoder, and passes only pointer and length values to the parsing function.
After parsing completes, the WASM engine returns a 64-bit packed integer containing memory offset and payload length for serialized AST results. The JavaScript client reads this buffer directly through typed array views without intermediary serialization overhead.
Binary Size Reduction and Symbol Stripping
Unoptimized Rust WebAssembly outputs often exceed 2.5 MB due to formatting strings, panic handling machinery, and symbol tables. Bosun enforces strict release profile flags in Cargo.toml.
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
strip = trueThese configuration flags instruct the LLVM compiler to optimize purely for code size, inline across crate boundaries, and discard debugging symbols. Applying wasm-opt -Oz in CI post-processing strips dead functions and reorders functions to maximize gzip compression efficiency.
Replacing the default memory allocator with a compact 2KB slab allocator trims an additional 28 KB from the compiled output.
Web Worker Isolation and Parallel Dispatch
Parsing syntax trees must not block browser layout or UI rendering. The compiled WASM binary loads inside a dedicated HTML5 Web Worker.
Communication between the UI thread and the Web Worker uses postMessage with transferable ArrayBuffer instances. Transferring buffer ownership hands memory across thread contexts without cloning memory pages.
This architecture keeps main-thread frame rates locked at 60 FPS while processing background document imports and complex graph index queries.
WASM Engine Performance and Bundle Profile
The table below details binary size reductions and execution throughput across different optimization levels for the WebAssembly build.
| Build Stage / Profile | Raw WASM Size | Gzipped Size | Cold Instantiation Time | Parsing Throughput |
|---|---|---|---|---|
| Debug Target | 4.82 MB | 1.12 MB | 42.0 ms | 18 MB/s |
| Standard Release (-O3) | 1.45 MB | 382 KB | 12.4 ms | 142 MB/s |
| Size Optimized (-Oz + LTO) | 480 KB | 142 KB | 4.1 ms | 136 MB/s |
| wasm-opt -Oz Stripped | 318 KB | 98 KB | 2.8 ms | 134 MB/s |
- Directus Target: bosunpkm-blog
- Garden Source Reference: MOC - Bosun PKM Engine, MOC - Bosun PKM Tools, MOC - The Plain-Text Longevity Standard