DEV Community

daniel orihuela
daniel orihuela

Posted on Originally published at danielorihuela.dev on

How to use WASM code from ClojureScript through JavaScript interop

Clojure is a great programming language. I have been working with it lately, and it’s been a blast. Another language that I love is Rust. One day I was thinking about both languages, their advantages and disadvantages, and under which circumstances I should use each. That made me wonder if it would be hard to use WASM from Clojurescript.

My idea was to:

  1. Create a simple function in Rust
  2. Use wasm-bindgen crate to generate the WASM code and JavaScript bindings.
  3. Load the code into JavaScript
  4. Call WASM code from ClojureScript through the JavaScript interops

You can check the final code athttps://github.com/danielorihuela/wasm-on-clojurescript-through-js-interop.

The first two steps were easy. I created a simple Rust function.

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn add(a: u8, b: u8) -> u8 {
    a + b
}
Enter fullscreen mode Exit fullscreen mode

Then, I built the WASM code and JavaScript bindings with the following command:

wasm-pack build --target web
Enter fullscreen mode Exit fullscreen mode

Now is when the interesting part starts. We want to use the generated JavaScript bindings to call the WASM code. First, we need to create a simple website and load the code in the browser. In our case, we want to access the WASM functions from the “windows” object. So I ended up with the following piece of code.

<script type="module">
  import init, { add } from './wasm/addition.js'

  async function run() {
    await init();
    window.addWasm = add;
  }

  await run();
</script>
Enter fullscreen mode Exit fullscreen mode

The WASM is now loaded. We are ready to execute the “hello world” website.

clj -M --main cljs.main --compile hello-world.core --repl
Enter fullscreen mode Exit fullscreen mode

But there’s one problem.

The wasm file cannot be validated. I suspect it is related to Will Cohen’s comment on https://clojure.atlassian.net/browse/CLJS-3387. So I tried to serve it withminiserve. It worked!

We can call WASM code with with the following approach: Thecheatsheet tells us how to access the function we jsut exported.

(. js/window (addWasm 5 10))
Enter fullscreen mode Exit fullscreen mode

You can check the final code athttps://github.com/danielorihuela/wasm-on-clojurescript-through-js-interop.

And this is how we can call WASM from ClojureScript from a basic project. The problem with that approach is that we lost the REPL since we cannot use the ClojureScript browser. However, you will probably use a build tool likeshadow-cljs. An approach exists for shadow-cljs to use WASM with the REPL. You can check ithttps://github.com/thheller/wasm-pack-cljs.

Top comments (0)