Skip to main content

Embedding Raven in JS/TS

Interop runs both ways: a Raven module can be built into a JS file and imported from JavaScript or TypeScript like any other module.

Exporting functions

Exported Raven functions are emitted as async JS functions:

math.rv
export { add }

fn add(a: JSObject, b: JSObject) { Int32(a) + Int32(b) }
$ raven build --js math.rv
import { add } from './math.js'
console.log(await add(2, 3))

Arguments arrive from JS as JSObjects; convert them at the boundary (Int32(a), String(s), ...) and let the results convert back.

Build options

$ raven build --js hello.rv # hello.js + hello.wasm
$ raven build --js --embed hello.rv # single file, wasm embedded
$ raven build --js --esbuild hello.rv # esbuild-compatible wasm imports

The emitted script runs directly (./hello.js – it gets a shebang and executable permissions), or with Node explicitly. Prior to Node 25 you'll need node --experimental-wasm-jspi.

With Bun you can go all the way to a self-contained native binary:

$ raven build --js --esbuild hello.rv
$ bun build --compile hello.js
$ ./hello
Cacaw, World!

In a web project

For using Raven inside a bundled web app (Vite, esbuild etc), start from the raven-js-template repo, which wires up a working build. The --esbuild flag makes the wasm import play nicely with bundlers.

Raven code in the browser can call the DOM directly – so the split between "Raven for the logic, JS for the page" is yours to draw wherever you like.