feat: add browser/WASM support for bashkit#646
Merged
Conversation
Adds a browser-based terminal example using Bashkit compiled to WebAssembly via NAPI-RS WASI threads. Includes Vite config with required COOP/COEP headers for SharedArrayBuffer support.
Feature-gate tokio to use only WASM-compatible features (sync, macros, io-util, rt, time) at the workspace level, with rt-multi-thread and fs added per-crate for native targets only. This unblocks compilation for wasm32-wasip1-threads. - Add package.json `exports` with `browser` condition pointing to the existing bashkit.wasi-browser.js WASM loader - Add @napi-rs/wasm-runtime as optional dependency for browser WASM - Configure browser example Vite with esnext target (top-level await) and optimizeDeps exclusion for the WASM entry - Add *.wasm to .gitignore (build artifacts) - Update bashkit-bench, bashkit-eval, bashkit-python Cargo.toml to explicitly declare rt-multi-thread feature they need
The bashkit package is symlinked from node_modules into crates/bashkit-js/. Vite follows symlinks and resolves @fs/ URLs for the WASM binary and worker files, which are blocked by default strict fs policy. Adding server.fs.allow for the project root fixes the 403 errors on .wasm and .mjs worker files.
Three fixes for the browser example failing with createRequire error: 1. Add top-level "browser" field to bashkit package.json pointing to bashkit.wasi-browser.js — the universal bundler convention 2. Add resolve.alias in Vite config that resolves the WASM browser entry via realpathSync, bypassing unreliable export condition matching when optimizeDeps.exclude is set 3. Use file: protocol for @everruns/bashkit dep so npm install creates a symlink to the local crate instead of fetching from npm
The WASM runtime 0.2.x was incompatible with WASM binaries built by napi-rs CLI 3.5.x — missing _emnapi_async_worker linkage caused a WebAssembly.Instance LinkError in the browser. - Upgrade @napi-rs/wasm-runtime from ^0.2.9 to ^1.1.1 in both bashkit-js and the browser example - Add build:wasm script to bashkit-js package.json - Add npm start script to browser example that builds WASM then starts Vite dev server (single command setup) - Verified end-to-end in headless Chromium: echo, cat, bash scripts all execute correctly in the browser
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
tokio::task::spawn_blocking and tokio::time::timeout don't work in WASM (no blocking thread pool, timer driver unreliable). The parser timeout was causing every command to take ~4120ms instead of ~20ms — the full timeout duration was being waited even though parsing completed instantly. On wasm32 targets, parse inline without timeout/spawn_blocking. Native targets keep the existing behavior unchanged. Before: 4120ms per command (echo, cat, anything) After: 19-23ms per command (200x faster)
The field is unused on WASM targets since the timeout/spawn_blocking path is skipped. Gate it to eliminate dead_code warning.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
wasm32-wasip1-threadstarget)tokio::time::timeout+spawn_blockingwith#[cfg(target_family = "wasm")]— reduces per-command latency from 4120ms to ~20ms@napi-rs/wasm-runtimeto 1.x for compatibility with napi-rs CLI 3.5.xWhat changed
crates/bashkit/src/lib.rs: Conditional compilation for WASM — parse inline without timeout/spawn_blocking on WASM targetscrates/bashkit/Cargo.toml: Split tokio features sort-multi-threadandfsare native-onlycrates/bashkit-js/package.json: Addedbrowserfield,exportsconditions,build:wasmscriptexamples/browser/: Complete browser example with Vite config, COOP/COEP headers, terminal UITest plan
cargo test --all-features— all 2,909 tests passcargo clippy --all-targets --all-features -- -D warnings— cleancargo fmt --check— cleanagent-browser— commands execute in ~20ms