Leptos & wasm-bindgen

note to self: its tricksy


Josiah Parry


January 15, 2024

As a side project, I’m trying to build a full stack web app with auth, session management etc. I do data science and no web-dev. I am very out of my element. But no better way to learn than trial by fire.

I’m doing all of this through the Rust leptos framework. But the challenge is that javascript is always present and I can’t really get away from it for some things and making the two interact is honestly super tricky and is probably where most of my frustration with leptos has come from.

To be able to call javascript from your leptos app. You need to use something called wasm-bindgen. This lets you call javascript functions from Rust.

Part of what I’m playing with involves webR. And I have a javascript file like so:

import { WebR, Console } from 'https://webr.r-wasm.org/latest/webr.mjs';

const webR = new WebR();
await webR.init();

/* Create a webR console using the Console helper class */
const webRConsole = new Console();
console.log("webR console started");
webRConsole.stdin("options('max.print' = 1000)");

// a bunch of other stuff that fetches things from the DOM

export async function resize_plot(w, h) {
    var call = "options(device = webr::canvas(" + w + ", " + h + "))";
    var res = webRConsole.stdin(call);

which will load webR at the start and exports a function to resize the plot window.

Now in a rust file I have:

use wasm_bindgen::prelude::*;

// create rust functions from the javascript functions
#[wasm_bindgen(module = "/webr.js")]
extern "C" {
    pub fn resize_plot(w: f64, h: f64) -> JsValue;

This lets me call resize_plot() directly from my rust code which is super cool! However, because of the way that wasm-bindgen works, whatever is not contained inside of a function is execute on every single page even where it is not needed.

Because I have resize_plot() called in one of my leptos components it gets imported in the site-wide javascript via wasm-bindgen at /pkg/myapp.js.

import { resize_plot } from './snippets/myapp-aa4c1e3078dc6708/webr.js';

On pages where this code isn’t needed or uses errors can abound which will break client side reactivity in leptos.

Now it’s a matter of having to figure out how to appropriately import and expose javascript functions so that no errors arise with wasm-bindgen.

In one case, I was able to move everything over to pure javascript which is fine. I’m unsure how I will handle others.