-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8b32f0b
commit 6ebcd1e
Showing
15 changed files
with
707 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
# "Hello world" with statue | ||
|
||
Using ["Hello world" without statue](./hello_world_without_statue.md) as a starting point, we can update it to use `statue` for querying selectors. | ||
|
||
## wb-hello-world/wb-hello-world/Cargo.toml | ||
|
||
Find the dependencies in the `Cargo.toml` file: | ||
|
||
```toml | ||
[dependencies] | ||
wasm-bindgen = "0.2.84" | ||
console_error_panic_hook = { version = "0.1.7", optional = true } | ||
|
||
[dependencies.web-sys] | ||
version = "0.3.4" | ||
features = [ | ||
'Document', | ||
'Element', | ||
'HtmlElement', | ||
'HtmlInputElement', | ||
'Window', | ||
'EventTarget', | ||
'InputEvent' | ||
] | ||
``` | ||
|
||
And add the `statue` dependency: | ||
|
||
```toml | ||
[dependencies] | ||
wasm-bindgen = "0.2.84" | ||
console_error_panic_hook = { version = "0.1.7", optional = true } | ||
statue = "0.3" | ||
|
||
[dependencies.web-sys] | ||
version = "0.3.4" | ||
features = [ | ||
'Document', | ||
'Element', | ||
'HtmlElement', | ||
'HtmlInputElement', | ||
'Window', | ||
'EventTarget', | ||
'InputEvent' | ||
] | ||
``` | ||
|
||
## wb-hello-world/wb-hello-world/src/lib.rs | ||
|
||
Replace the initialization of the elements with manual querying selectors and casting to the desired types: | ||
|
||
```rust | ||
let window = web_sys::window().unwrap(); | ||
let document = window.document().unwrap(); | ||
|
||
let header = document.query_selector("h1").unwrap().unwrap(); | ||
let name_input = document.get_element_by_id("name-input").unwrap() | ||
.dyn_into::<web_sys::HtmlInputElement>().unwrap(); | ||
``` | ||
|
||
to the invocation of the `statue::initialize_elements` macro: | ||
|
||
```rust | ||
initialize_elements!{ | ||
html: "../index.html", | ||
elements: { | ||
let header = Single("h1"); | ||
let name_input = Single("#name-input"); | ||
} | ||
}; | ||
``` | ||
|
||
*Note: the various aspects of the syntax of the macro will be discussed in the `Syntax` section of the guide*. | ||
|
||
Also, update the `use` statements from this: | ||
|
||
```rust | ||
use utils::set_panic_hook; | ||
use wasm_bindgen::prelude::*; | ||
``` | ||
|
||
to this: | ||
|
||
```rust | ||
use utils::set_panic_hook; | ||
use wasm_bindgen::prelude::*; | ||
use statue::initialize_elements; | ||
``` | ||
|
||
## Build the project | ||
|
||
Once you have the `Cargo.toml` and `lib.rs` files set up, build the project: | ||
|
||
```console | ||
cd wb-hello-world | ||
wasm-pack build --target web | ||
cd .. | ||
``` | ||
|
||
This will create a `pkg` directory in the `wb-hello-world` directory, and the `pkg` directory will contain the `wb_hello_world.js` file, among others. | ||
|
||
## Run the project | ||
|
||
> **Note**: You cannot directly open `index.html` in your web browser due to [CORS][cors] | ||
> limitations. Instead, you can set up a quick development environment using | ||
> Python's built-in HTTP server: | ||
> | ||
> ```console | ||
> wasm-pack build --target web | ||
> python3 -m http.server 8080 | ||
> ``` | ||
> | ||
> If you don't have Python installed, you can also use [miniserve][miniserve] which | ||
> is installable via Cargo: | ||
> | ||
> ```console | ||
> cargo install miniserve | ||
> miniserve . --index "index.html" -p 8080 | ||
> ``` | ||
[cors]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS | ||
[miniserve]: https://crates.io/crates/miniserve | ||
## About the advantages of using `statue` | ||
Even in this simple example, using `statue` has some benefits: | ||
* You can enjoy the benefits of using contextual suggestions and type inference in your IDE, since the `statue` macro invocation expands to strongly-typed expressions with inferred types. | ||
* If you make a typo in the selector, the `statue` macro invocation will fail to compile, which will help you catch the errors at compile time. | ||
* If there are breaking changes in `index.html`, the `statue` macro invocation will fail to compile, which will help you catch the errors early. | ||
* You can use the familiar CSS selector syntax to query elements instead of picking the right method from the `web_sys` API. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
# Hello world without statue | ||
|
||
First of all, we will create a simple webpage that displays `"Hello, <name>"` with `wasm_bindgen` **but without `statue`**. This will help you understand the basics of Rust and WebAssembly for browsers. | ||
|
||
Go to an empty directory: | ||
|
||
```console | ||
mkdir wb-hello-world | ||
cd wb-hello-world | ||
``` | ||
|
||
## wb-hello-world/index.html | ||
|
||
In this empty directory, create the `index.html` with the following contents: | ||
|
||
```html | ||
<html> | ||
<head> | ||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/> | ||
</head> | ||
<body> | ||
<script type="module"> | ||
import init from './wb-hello-world/pkg/wb_hello_world.js'; | ||
init(); | ||
</script> | ||
<h1>Hello, friend!</h1> | ||
<input type="text" placeholder="Enter your name" id="name-input"> | ||
</body> | ||
</html> | ||
``` | ||
|
||
This is a simple HTML file that has | ||
|
||
* An `ES6` module that imports the `hello_world` package and calls the `init` function, | ||
* An `h1` element that in the absence of JS or WASM displays `"Hello, friend!"`, | ||
* An `input` element that allows the user to enter their name. | ||
|
||
If we were to run a `tree` command in the `wb-hello-world` directory, we would see the following: | ||
|
||
```text | ||
index.html | ||
``` | ||
|
||
## wb-hello-world/wb-hello-world | ||
|
||
Ensure that you have [`wasm-pack`](https://rustwasm.github.io/wasm-pack/) installed: | ||
|
||
```console | ||
wasm-pack --version | ||
``` | ||
|
||
With `wasm-pack` installed, create a new Rust WASM project: | ||
|
||
```console | ||
wasm-pack new wb-hello-world | ||
``` | ||
|
||
If you were to run a `tree` command in the `wb-hello-world` directory again, you would see the following: | ||
|
||
```text | ||
index.html | ||
wb-hello-world | ||
├───src | ||
│ ├───lib.rs | ||
│ └───utils.rs | ||
├───Cargo.toml | ||
................. | ||
└───tests | ||
``` | ||
|
||
What matters to us is that the nested `wb-hello-world` directory is a Rust library that we can build into a WASM package. | ||
|
||
## wb-hello-world/wb-hello-world/Cargo.toml | ||
|
||
Find the `[dependencies]` section in the `Cargo.toml` file of the Rust library: | ||
|
||
```toml | ||
[dependencies] | ||
wasm-bindgen = "0.2.84" | ||
|
||
# The `console_error_panic_hook` crate provides better debugging of panics by | ||
# logging them with `console.error`. This is great for development, but requires | ||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for | ||
# code size when deploying. | ||
console_error_panic_hook = { version = "0.1.7", optional = true } | ||
``` | ||
|
||
and add more dependencies: | ||
|
||
```toml | ||
[dependencies] | ||
wasm-bindgen = "0.2.84" | ||
console_error_panic_hook = { version = "0.1.7", optional = true } | ||
|
||
[dependencies.web-sys] | ||
version = "0.3.4" | ||
features = [ | ||
'Document', | ||
'Element', | ||
'HtmlElement', | ||
'HtmlInputElement', | ||
'Window', | ||
'EventTarget', | ||
'InputEvent' | ||
] | ||
``` | ||
|
||
Each of them will play a role in our project: | ||
|
||
* `wasm-bindgen` will allow us to expose Rust functions to JavaScript. | ||
* `console_error_panic_hook` will provide better debugging of panics, if any occur, by logging them with `console.error`. | ||
* `web-sys` will provide bindings to the Web APIs. | ||
|
||
## wb-hello-world/wb-hello-world/src/lib.rs | ||
|
||
Replace the contents of the `lib.rs` file with the following: | ||
|
||
```rust | ||
mod utils; | ||
|
||
use utils::set_panic_hook; | ||
use wasm_bindgen::prelude::*; | ||
|
||
#[wasm_bindgen(start)] | ||
pub fn start() { | ||
set_panic_hook(); | ||
|
||
let window = web_sys::window().unwrap(); | ||
let document = window.document().unwrap(); | ||
|
||
let header = document.query_selector("h1").unwrap().unwrap(); | ||
let name_input = document.get_element_by_id("name-input").unwrap() | ||
.dyn_into::<web_sys::HtmlInputElement>().unwrap(); | ||
|
||
{ | ||
let closure = Closure::<dyn FnMut(_)>::new(move |event: web_sys::InputEvent| { | ||
let input_element = event.target().unwrap().dyn_into::<web_sys::HtmlInputElement>().unwrap(); | ||
let name = input_element.value(); | ||
header.set_inner_html(&format!("Hello, {name}!")); | ||
}); | ||
name_input.add_event_listener_with_callback("input", closure.as_ref().unchecked_ref()).unwrap(); | ||
closure.forget(); | ||
} | ||
} | ||
``` | ||
|
||
This code does the following: | ||
|
||
* Adds `wb-hello-world/wb-hello-world/src/utils.rs` as a module called `utils`. | ||
* Imports the `set_panic_hook` function from the `utils` module. | ||
* Imports the [`wasm_bindgen` prelude](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen/prelude/index.html). | ||
* Defines a `start` function that will be called when the WASM module is loaded. | ||
|
||
The `start` function does the following: | ||
|
||
* Calls the `set_panic_hook` function to set up better debugging of panics. | ||
* Gets the `window` and `document` objects from the Web APIs. | ||
* Queries the `h1` element and the `name-input` element. Since `web_sys` doesn't have a dedicated type for `h1` elements, we keep the type of the `header` variable as [`web_sys::Element`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Element.html). | ||
* Creates a closure that is then added as a listener to the `input` event on the `name_input` element. The closure updates the `h1` element with the text `"Hello, <name>!"` where `<name>` is the value of the `name_input` element. This pattern is described in the [official `wasm-bindgen` guide](https://rustwasm.github.io/docs/wasm-bindgen/examples/closures.html). | ||
|
||
## Build the project | ||
|
||
Once you have the `Cargo.toml` and `lib.rs` files set up, build the project: | ||
|
||
```console | ||
cd wb-hello-world | ||
wasm-pack build --target web | ||
cd .. | ||
``` | ||
|
||
This will create a `pkg` directory in the `wb-hello-world` directory, and the `pkg` directory will contain the `wb_hello_world.js` file, among others. | ||
|
||
## Run the project | ||
|
||
> **Note**: You cannot directly open `index.html` in your web browser due to [CORS][cors] | ||
> limitations. Instead, you can set up a quick development environment using | ||
> Python's built-in HTTP server: | ||
> | ||
> ```console | ||
> wasm-pack build --target web | ||
> python3 -m http.server 8080 | ||
> ``` | ||
> | ||
> If you don't have Python installed, you can also use [miniserve][miniserve] which | ||
> is installable via Cargo: | ||
> | ||
> ```console | ||
> cargo install miniserve | ||
> miniserve . --index "index.html" -p 8080 | ||
> ``` | ||
[cors]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS | ||
[miniserve]: https://crates.io/crates/miniserve |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Examples of using `statue` | ||
|
||
This section contains examples of using the `statue`, `wasm-bindgen`, `js-sys`, and `web-sys` crates, as well as `wasm-pack` CLI tool. Each example should have more information about what it's doing. |
Oops, something went wrong.