Skip to content

amesgen/jsaddle-wasm

Repository files navigation

jsaddle-wasm

Run JSaddle JSM actions with the GHC WASM backend.

This can for example be used to compile and run Miso or Reflex apps in the browser.

Important

This project is in an early stage.

Examples

Miso

Several Miso examples: https://github.com/tweag/ghc-wasm-miso-examples

How to use

Install a WASM-enabled GHC with support for the WASM JSFFI from ghc-wasm-meta (GHC 9.10 or newer).

Assuming you built your application as an app :: JSM ():

import Language.Javascript.JSaddle.Wasm qualified as JSaddle.Wasm

foreign export javascript "hs_start" main :: IO ()

main :: IO ()
main = JSaddle.Wasm.run app

Build the WASM binary with the following GHC options:

ghc-options: -no-hs-main -optl-mexec-model=reactor "-optl-Wl,--export=hs_start"

Now, run the post-linker script as described in the GHC User's Guide; we will call the resulting JavaScript file ghc_wasm_jsffi.js.

Then, following the GHC User's Guide, you can run the WASM binary in the browser via e.g. browser_wasi_shim:

import { WASI, OpenFile, File, ConsoleStdout } from "@bjorn3/browser_wasi_shim";
import ghc_wasm_jsffi from "./ghc_wasm_jsffi.js";

const fds = [
  new OpenFile(new File([])), // stdin
  ConsoleStdout.lineBuffered((msg) => console.log(`[WASI stdout] ${msg}`)),
  ConsoleStdout.lineBuffered((msg) => console.warn(`[WASI stderr] ${msg}`)),
];
const options = { debug: false };
const wasi = new WASI([], [], fds, options);

const instance_exports = {};
const { instance } = await WebAssembly.instantiateStreaming(fetch("app.wasm"), {
  wasi_snapshot_preview1: wasi.wasiImport,
  ghc_wasm_jsffi: ghc_wasm_jsffi(instance_exports),
});
Object.assign(instance_exports, instance.exports);

wasi.initialize(instance);
await instance.exports.hs_start();

Potential future work

  • Take a closer look at synchronous callbacks (no special handling currently, but basic things like stopPropagation already seem to work fine).
  • Testing (e.g. via Selenium).
  • Add logging/stats.
  • Performance/benchmarking (not clear that this is actually a bottleneck for most applications).
    • Optimize existing command-based implementation.
      • Reuse buffers
      • Use a serialization format more efficient than JSON.
    • Skip JSaddle commands, use WASM JSFFI more directly. Not clear if this is worth the extra complexity.

Related projects

About

JSaddle integration for the GHC WASM backend

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published