Running gbash in the Browser
gbash compiles to WebAssembly, letting you run a full shell runtime in the browser with no server-side execution.
Build pipeline
The WASM artifact is built from the Go source using the js/wasm target. The build produces two files:
gbash.wasm-- the compiled runtimewasm_exec.js-- the Go WASM support script (from the Go toolchain)
The @ewhauser/gbash-wasm package handles building and bundling these artifacts. In the website project, pnpm build compiles the WASM from source and copies both files into public/.
Loading in a web app
Import the Bash class from @ewhauser/gbash-wasm/browser:
import { Bash } from "@ewhauser/gbash-wasm/browser";
const bash = new Bash({
cwd: "/home/agent",
env: { TERM: "xterm-256color" },
files: {
"/home/agent/hello.txt": "Hello from gbash!\n",
},
});
const result = await bash.exec("cat /home/agent/hello.txt");
console.log(result.stdout); // "Hello from gbash!\n"
console.log(result.stderr); // ""
console.log(result.exitCode); // 0The runtime loads lazily on first use. It fetches wasm_exec.js and gbash.wasm, boots the Go runtime, and waits for window.GBashWasm to register. Subsequent Bash instances reuse the same loaded runtime.
You can override asset URLs if you host the files elsewhere:
const bash = new Bash({
wasmUrl: "/assets/gbash.wasm",
wasmExecUrl: "/assets/wasm_exec.js",
});Pre-seeding files
Pass a files map in the constructor to populate the in-memory filesystem before execution:
const bash = new Bash({
files: {
"/data/config.json": '{"key": "value"}',
"/scripts/setup.sh": "echo ready",
},
});You can also write files after initialization:
bash.writeFile("/data/input.csv", csvContent);Custom commands in JavaScript
Register custom commands that execute as JavaScript functions:
import { Bash, defineCommand } from "@ewhauser/gbash-wasm/browser";
const bash = new Bash({
customCommands: [
defineCommand("now", async () => ({
stdout: new Date().toISOString() + "\n",
stderr: "",
exitCode: 0,
})),
],
});
const result = await bash.exec("now");Custom commands are matched before the WASM runtime for simple command invocations, so they can override or extend built-in commands.
CSP headers
WebAssembly compilation requires the wasm-unsafe-eval CSP directive. Add it to your Content-Security-Policy header:
Content-Security-Policy: script-src 'self' 'wasm-unsafe-eval';
Without this directive, browsers will block WASM instantiation.
Cleanup
Dispose of the shell when you are done to release WASM resources:
await bash.dispose();Reference
The website directory contains a full Next.js app running gbash in the browser via WASM, including terminal UI integration.