WebAssembly
If you want to use a systems programming language like Rust or C++, you can compile it to WebAssembly (WASM). Your WASM code can then drive the DOM or canvas directly. You only need the allowed shell tags (<html>, <head>, <body>, <meta>, <script>, <style>, and <canvas>) to load the WebAssembly, keeping the rest of your UI out of literal HTML.
Here is a step-by-step guide to doing this with Rust and web-sys.
Step 1: Rust Setup
First, you'll need a Rust function that runs when the WASM module loads. We use wasm_bindgen to communicate between Rust and JavaScript.
use wasm_bindgen::prelude::*;
use web_sys::{window, HtmlCanvasElement, CanvasRenderingContext2d};
// This attribute tells wasm-pack to run this function immediately upon loading
#[wasm_bindgen(start)]
pub fn main() -> Result<(), JsValue> {
// 1. Get the global window and document objects
let document = window().unwrap().document().unwrap();
// 2. Create a canvas element dynamically via Rust!
// We cast it to HtmlCanvasElement so we can access canvas-specific methods.
let canvas = document
.create_element("canvas")?
.dyn_into::<HtmlCanvasElement>()?;
// 3. Set the dimensions of the canvas
canvas.set_width(800);
canvas.set_height(600);
// 4. Append it to the document body
document.body().unwrap().append_child(&canvas)?;
// 5. Get the 2D rendering context
let ctx = canvas
.get_context("2d")?
.unwrap()
.dyn_into::<CanvasRenderingContext2d>()?;
// 6. Draw a pink rectangle on the canvas, entirely from Rust!
ctx.set_fill_style_str("#e94560");
ctx.fill_rect(100.0, 100.0, 300.0, 200.0);
Ok(())
}
Step 2: Build the WebAssembly
Once your Rust code is ready, you need to compile it to WebAssembly targeting the web.
Run this command in your terminal:
wasm-pack build --target web
This generates a .wasm file and a JavaScript wrapper that makes it easy to load in the browser.
Step 3: Load the WASM from HTML
Finally, in your tagless HTML shell, you use an allowed <script> tag to import the generated JS module and initialize it.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<!-- Load the JS wrapper generated by wasm-pack -->
<script type="module">
import init from './pkg/your_project_name.js';
// Initialize the WASM module, which automatically calls your #[wasm_bindgen(start)] function!
init();
</script>
</body>
</html>
Useful references:
- wasm-pack quickstart
- Rust and WebAssembly book
- Go WASM - Go ships WASM support in the standard toolchain
