Running In A Browser Using WebAssembly

Right now, we used cargo run to build and run our program as a native application. Native applications are the primary target of the Slint framework, but we also support WebAssembly for demonstration purposes. So in this section we'll use the standard rust tool wasm-bindgen and wasm-pack to run the game in the browser. The wasm-bindgen documentation explains all you need to know about using wasm and rust.

Make sure to have wasm-pack installed using

cargo install wasm-pack

You'll need to edit your Cargo.toml to add the dependencies.

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = { version = "0.2" }
getrandom = { version = "0.2.2", features = ["js"] }

The 'cfg(target_arch = "wasm32")' ensures that these dependencies will only be active when compiling for the wasm32 architecture. Note that the rand dependency is now duplicated, in order to enable the "wasm-bindgen" feature.

While you are editing the Cargo.toml, one last change is needed: you need to turn the binary into a library by adding the following:

[lib]
path = "src/main.rs"
crate-type = ["cdylib"]

This is required because wasm-pack require rust to generate a "cdylib".

You also need to modify the main.rs by adding the wasm_bindgen(start) attribute to the main function and export it with the pub keyword:

#[cfg_attr(target_arch = "wasm32",
           wasm_bindgen::prelude::wasm_bindgen(start))]
pub fn main() {
    //...
}

Now, we can compile our program with wasm-pack build --release --target web. This will create a pkg directory containing a few files, including a .js file named after your program name. We just have to import that from a HTML file. So let's create a minimal index.html that declares a <canvas> element for rendering and loads our generated wasm file. The Slint runtime expects the <canvas> element to have the id id = "canvas". (Replace memory.js by the correct file name).

<html>
    <body>
        <!-- canvas required by the Slint runtime -->
        <canvas id="canvas"></canvas>
        <script type="module">
            // import the generated file.
            import init from "./pkg/memory.js";
            init();
        </script>
    </body>
</html>

Unfortunately, loading ES modules isn't allowed for files on the file system when accessed from a file:// URL, so we can't simply open the index.html. Instead we need to serve it through a web server. For example, using Python, it's as simple as running

python3 -m http.server

and then you can now access the game on http://localhost:8000.