How-To: Run wasm32-wasi Output in Node.js
This guide shows how to:
- compile a Silk program to
wasm32-wasi, and - run it under Node’s built-in WASI runtime (
node:wasi), and - forward process arguments into Silk.
The wasm32-wasi backend emits a _start () -> void entrypoint that calls Silk
fn main () -> int and then calls wasi_snapshot_preview1.proc_exit(exit_code).
1) Build a WASI Module#
Create main.slk:
import io from "std/io";
fn main () -> int {
io::println("hello from silk wasm wasi");
return 0;
}
Build:
silk build main.slk --target wasm32-wasi -o out.wasm
2) Run it with node:wasi#
Create run.js:
const fs = require('node:fs');
const { WASI } = require('node:wasi');
async function main() {
const wasmPath = process.argv[2];
const userArgs = process.argv.slice(3);
const wasi = new WASI({ version: 'preview1', args: [wasmPath, ...userArgs], env: {}, preopens: {} });
const bytes = fs.readFileSync(wasmPath);
const { instance } = await WebAssembly.instantiate(bytes, wasi.getImportObject());
try {
wasi.start(instance);
} catch (err) {
// Some Node versions throw on proc_exit; the exit code is still available.
}
const exitSym = Object.getOwnPropertySymbols(wasi).find((s) => s.toString() === 'Symbol(kExitCode)');
const code = (exitSym && typeof wasi[exitSym] === 'number') ? wasi[exitSym] : (process.exitCode ?? 0);
process.exit(code);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
Run:
node --no-warnings run.js out.wasm
echo $?
Expected output:
- stdout contains
hello from silk wasm wasi - exit code is
0
3) Access argv from fn main () -> int#
The WASI entrypoint remains parameterless. Read arguments through std::args
inside main:
import { current } from "std/args";
import { println } from "std/io";
fn main () -> int {
let args = current();
println("argc={}", args.count());
if args.count() > 1 {
println("argv[1]={}", args.get(1));
}
return 0;
}
Pass user arguments after the .wasm path:
node --no-warnings run.js out.wasm alpha beta
Silk then sees out.wasm, alpha, and beta as argv[0], argv[1], and
argv[2].
Troubleshooting#
- If you see missing-import errors mentioning
wasi_snapshot_preview1, confirm you built with--target wasm32-wasi(notwasm32-unknown-unknown). task/yieldandasync/awaitdo not yet have a WASM concurrency runtime.- WASI is a constrained environment. Shipped modules such as
std::args,std::env, and parts ofstd::fsuse the WASI runtime surface; unsupported OS facilities can still fail code generation or return runtime errors. - For deeper backend details and entrypoint behavior, see: WASM backend.
Source repository · Edit this page · View Markdown