A Simple Tutorial for Writing a Rust Program for the Web

As you surely know, a web page/site is simply some content made available to your computer, which is not stored on your computer, but rather "out there" somewhere "on the web". Web sites are built on HTML (HyperText Markup Language), which is just plain text wrapped up in "tags" that specify things like "this is the title of the page" and "this word should be displayed in the color blue", etc, and then these plain-text pages are "served" to the world-wide web from web servers. Your web-browser (Opera, Firefox. Chrome, Edge, Safari, whatever) goes to the desired site's URL (Uniform Resource Locater) address, and the server then serves its webpages to your browser which displays it to your eyes on your computer's screen. Your web-browser is the "client", and the web-server is the "server". The server serves the web site to the client.

But sometimes, the content of a web site needs to be more complex than plain text can provide. For this, you need to be able to "program" the web page/site. This can be done on the server (the "back-end"), or on the client (the "front-end"). The "standard" back-end programming language is php; the "standard" front-end language is Javascript.

Most web-browsers understand Javascript natively; Javascript is built-into most web-browsers.

Most web-browsers can also accept "plugins" (or "add-ins", or similar terminology). These plugins can add support for other client-side programming languages, such as Java (not to be confused with Javascript, a completely different critter) or Flash (used to be popular but is now deprecated).

The "front-end" for web applications has typically been HTML + Javascript + a web browser. With 'WebAssembly' (wasm), the future may be HTML + any language you want to use, including Rust, + wasm "virtual machine" + a web browser. Additionally, the future may also be without the web browser, as the wasm virtual machine (VM) can run wasm apps without a web browser. It's basically what Java was supposed to be, only faster, and not tied to a particular ("Java") language.

There are several pieces which you need to start to understand. We'll tackle them one at a time.

A Very Simple Rust Program

You should be able to create a "Hello, World!"-type program in Rust and compile it and run it; you should be able to find and run the compiled executable. For example, a project named "testbed":

main.rs
fn main() {
  println!("This is an example.");
} // end of main()
$ cargo build
$ ./target/debug/testbed

If you need help on installing Rust or writing/compiling/running the simple program above, see Have a working Rust Environment (on Debian).

When you build a Rust program, the Rust compiler typically has as its "target" a machine-language executable that the hardware understands, whether that hardware is an x86 chip or a Mac Silicon chip or a Raspberry Pi ARM chip or ... etc.

Add The "trunk" Crate to Your Rust Setup

Now use the Rust 'cargo' system to install 'trunk' into your Rust/Cargo system (a new 'trunk' directory will be created in '~/.cargo/bin'). 'trunk' is a Rust crate that will help in the process of packaging a Rust program for the web. Probably best to do this from your home directory:

$ cargo install trunk

I got an error because my version of 'rustc' was too old (1.68, needing 1.70). I fixed it by updating Rust:

$ rustup update

I then ran $ cargo install trunk again, which this time was successful.

'trunk' also functions as a simple web server. Perhaps you've used the Apache web server, or something similar; 'trunk' is much more basic.

You are probably aware that although there are strict rules for proper HTML, the HyperTextMarkupLanguage can be very forgiving. For example, use your favorite plain-text editor (such as "nano" on Debian) to create the following file, and name it "index.html".

index.html
Howdy, Earthlings!"

Then use your favorite web-browser's "File/Open File" feature to open this file. Your web-browser (you are using Firefox, aren't you, to help preserve Internet Freedom?) should display the contents of this file, even though it's not proper HTML.

Before going any farther, let's make this a proper HTML file.

index.html
<!DOCTYPE html>
<html lang="en">

<head>
<title>A Real HTML Page</title>
</head>

<body>
<p>Howdy, Earthlings!"</p>
</body>
<html>

Even though your file now contains proper HTML, it's still just a text file; it's not really a web page, because it's not being served by a web server. But if we use a web server, like 'Apache' or 'trunk', the file is more properly a web page.

So let's fire up 'trunk' as a web server, to serve this file. By default, it'll look for a file named "index.html" in the same directory from which 'trunk' is started, and by default it'll serve the file out to the web at the local computer's address ("http://localhost"), port # 8080.

$ trunk serve

If you get an error about the port already being used, you can Ctrl-C (if need be) and then restart the 'trunk' server, teling it to serve on a different port think of a port as a bank teller's window; all the windows (ports) allow you to get business done with the bank, but another customer may be at one, one may be closed, one may be dedicated to credit card business, etc.

$ trunk serve --port 8090

Unless you background this process by adding an & to the end of the command, this command will tie up your terminal window; you can kill the process with Ctrl-C, or kill it in one of the other traditional ways (e.g. kill <PID>).

Now point your web-browser's URL address bar to http://localhost:8080 (or substitute the different port number for 8080). Now you should see the same file you saw when you loaded it into your browser as a text file, but now you're seeing it as a web page. The only difference is that one is "served" from your computer's storage, and the other is served from your computer's web server.

You can create a different "index.html" file (with a different message) in a different directory, and start up a second instance of 'trunk' from that directory; just specify a different port (like 9000), and change the browser's URL address accordingly.

Install Web-Assembly

Now we need to install the web-assembly components into our Rust system:

$ rustup target add wasm32-unknown-unknown

As you know, web-browsers do not read and process executable files (like "helloworld.exe", which you might see on a Windows-based PC); rather, they read and process HTML files (along with a few other types, such as .css (Cascading Style Sheets) and .js (JavaScript), and a few other types, mostly depending on the browser; a few other types are used by web servers, such as .php. By and large, programs (applications) for browsers (the "front-end", vs servers, the "back-end") have typically been restricted to being written in Javscript and Typescript, or with plugins, things like Java (a different critter from Javascript, despite the similarity in names) and Flash (now deprecated and not much used anymore). One of the newest and most promising newcomers is WebAssembly (or wasm). This is basically a middle-layer compiler that takes programs written in higher-level languages such as Rust and C and Python, and converts them to something that is very near to being assembly language, but designed for the web. An extra perk of wasm that seems to be just around the corner is that it can run directly on the computer, without going through a web browser, and looks like it may tun out to be a "write-once, run-anywhere" technology.

Normally when you compile a Rust program, it compiles to an executable that is suitable for running it on the architecture (Windows, Linux. Mac, Android, etc) it targets; the command above installs the necessary pieces for a Rust program to be compiled, targeting the wasm "virtual machine" instead of the actual hardware on which it is compiled.

Create a Rust Project

cargo new web_example

Just like any other Rust project; move into whatever directory you're using for your projects, and use 'cargo' to create a new project:

$ cd ~/projects
~/projects$ cargo new web_example

Add the 'yew' Dependency

Before doing that, you might want to $ cat Cargo.toml just so you can compare the Before and After state of that file.

$ cat Cargo.toml
[package]
name = "web_example"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
$ cargo install trunk

In the old days, you had to manually edit 'Cargo.toml'. With newer versions of Rust, you can just...:

$ cargo add yew

And, of course, if you want to learn more about 'yew', you can web-browse over to https://crates.io" and Search for 'yew' to read more about it.