For our intermediate example, we will use the classic counter
example.
We will start by creating a new rust library project called counter
.
cargo new --lib counter
Modiy the Cargo.toml
to be a library of crate-type "cdylib", since we are compiling it for a web application.
Then add sauron
to our dependency.
[package]
name = "counter"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
sauron = "0.50.0"
In this example we will show 3 buttons where can click to increment/decrement and reset the count.
We will start by defining our model. Remove the contents of src/lib.rs
put this code.
use sauron::prelude::*;
struct App {
count: i32,
}
impl App {
fn new() -> Self {
App { count: 0 }
}
}
We also added a function new
to create our initial state of App
which starts with count 0
.
Next, we define out set of actions that our application will have. We will implement this using an enum
with name Msg
.
enum Msg {
Increment,
Decrement,
Reset,
}
Next, we implement the Application
trait for our model App
. This is a way to define how our app should be displayed on page with the view
method.
Additionally, this also let us define how the App
modifies its model with the update
method.
We also specify Msg
to the Application
trait which tells what type of messages that will be passed from events in the view
, which also corresponds to
the type we send into the update
method.
Append this code to src/lib.rs
.
use sauron::*;
impl Application for App {
type MSG = Msg;
fn view(&self) -> Node<Msg> {
node! {
<main>
<input type="button"
value="+"
on_click=|_| {
Msg::Increment
}
/>
<button class="count" on_click=|_|{Msg::Reset} >{text(self.count)}</button>
<input type="button"
value="-"
on_click=|_| {
Msg::Decrement
}
/>
</main>
}
}
fn update(&mut self, msg: Msg) -> Cmd<Msg> {
match msg {
Msg::Increment => self.count += 1,
Msg::Decrement => self.count -= 1,
Msg::Reset => self.count = 0,
}
Cmd::none()
}
}
The view
method creates a html node tree.
Notice, that the return type is Node<Msg>
which means it creates a html node where any of its member html elements has an event listener
that can emit a Msg
messages to the program handler.
When a user clicks on the +
button, this will emit an Msg::Increment
message.
The update
method accepts Msg
as an argument and modify our model App
depending on the variant of our Msg
.
For now, we return Cmd::none()
at the end of the update method. Cmd
is a way to tell the program to execute something, we will cover this in a more advanced example.
Next, we define an entry point for our wasm
web app.
This is done by anotating a public function with #[wasm_bindgen(start)]
.
Append this code to src/lib.rs
.
#[wasm_bindgen(start)]
pub fn start() {
Program::mount_to_body(App::new());
}
Inside this function, we define how our app is to be mounted into our index.html
page.
In this case we mount it to the body
of our html page.
The Program
object provides other methods on how to mount your application into the document.
Next, we need to link our application in a html page.
Put this in index.html
file at the project base folder.
You can put your styles as usual.
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
<title>Counter</title>
<style type="text/css">
body { font-family: verdana, arial, monospace; }
main {
width:30px;
height: 100px;
margin:auto;
text-align: center;
}
input, .count{
font-size: 40px;
padding: 30px;
margin: 30px;
}
</style>
<script type=module>
import init from './pkg/counter.js';
await init().catch(console.error);
</script>
</head>
<body>
</body>
</html>
Make sure that the filename of the javascript file (./pkg/counter.js
) in the import
file matches the package name of your web app (counter
).
Double check this part of the code especially if you change the package name of your web app.
Compile the web app by issuing the command:
wasm-pack build --release --target=web
You need to issue this command everytime you modify the rust code.
Finally, serve the files using basic-http-server
at port 4004
basic-http-server -a 0.0.0.0:4004
Then navigate your browser http://localhost:4004 to see and interact with the app.