console.log
This example shows off how to use console.log in a variety of ways, all the way from bare-bones usage to a println!-like macro with web_sys.
_ [wasm-bindgen Guide]
Original [wasm-bindgen Guide example]
PART I. Make it run
Converting Examples in 7 steps
1. Set up your file structure
cargo new console_log --lib
cd console_log
mkdir -p www/html www/js
2. Edit Cargo.toml, add crate-type and wasm-bindgen dependency
[package]
name = "console_log"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.88"
3. get the code
Cut and paste the console-log example [src/lib.rs] for console-log
#![allow(unused)] fn main() { // src/lib.rs use wasm_bindgen::prelude::*; #[wasm_bindgen(start)] fn run() { bare_bones(); using_a_macro(); using_web_sys(); } // First up let's take a look of binding `console.log` manually, without the // help of `web_sys`. Here we're writing the `#[wasm_bindgen]` annotations // manually ourselves, and the correctness of our program relies on the // correctness of these annotations! #[wasm_bindgen] extern "C" { // Use `js_namespace` here to bind `console.log(..)` instead of just // `log(..)` #[wasm_bindgen(js_namespace = console)] fn log(s: &str); // The `console.log` is quite polymorphic, so we can bind it with multiple // signatures. Note that we need to use `js_name` to ensure we always call // `log` in JS. #[wasm_bindgen(js_namespace = console, js_name = log)] fn log_u32(a: u32); // Multiple arguments too! #[wasm_bindgen(js_namespace = console, js_name = log)] fn log_many(a: &str, b: &str); } fn bare_bones() { log("Hello from Rust!"); log_u32(42); log_many("Logging", "many values!"); } // Next let's define a macro that's like `println!`, only it works for // `console.log`. Note that `println!` doesn't actually work on the wasm target // because the standard library currently just eats all output. To get // `println!`-like behavior in your app you'll likely want a macro like this. macro_rules! console_log { // Note that this is using the `log` function imported above during // `bare_bones` ($($t:tt)*) => (log(&format_args!($($t)*).to_string())) } fn using_a_macro() { console_log!("Hello {}!", "world"); console_log!("Let's print some numbers..."); console_log!("1 + 3 = {}", 1 + 3); } // And finally, we don't even have to define the `log` function ourselves! The // `web_sys` crate already has it defined for us. fn using_web_sys() { use web_sys::console; console::log_1(&"Hello using web-sys".into()); let js: JsValue = 4.into(); console::log_2(&"Logging arbitrary values looks like".into(), &js); } }
Note:
Since use web_sys::console;
brings into scope console
from the web-sys
crate we need to
declare it in our Cargo dependencies.
...
[dependencies]
wasm-bindgen = "0.2.92"
web-sys = { version = "0.3.69", features = ['console'] }`
or from the commandline
cargo add web-sys -F "console"
4. create the index file at www/html/index.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>nobundle: console_log</title>
</head>
<body>
<script type="module" src="../js/index.js"></script>
</body>
</html>
5. The js file
We could have written the file like this
import init, { run as run_me } from "../pkg/console_log.js";
async function run() {
const wasm = await init();
run_me();
}
run();
However it is not necessary in this case, because we used #[wasm_bindgen(start)]
in src/lib.rs
#![allow(unused)] fn main() { ... #[wasm_bindgen(start)] fn run() { bare_bones(); using_a_macro(); using_web_sys(); } ... }
Hence our js file can run directly
import init from "../pkg/console_log.js";
async function run() {
const wasm = await init();
}
run();
6. build it
wasm-pack build --target web --no-typescript --out-dir www/pkg
7. serve it
Note: Our index.html
is now in www/html/
http www
Open the browser at http://127.0.0.1:8000/html/
firefox http://localhost:8000/html/
and ctrl-shift + I
to see the output in the browsers console log
PART II. Understand the Code
Understand the Code
What's next?
There is nothing specific to nobundle in the [Small wasm files] example so we'll pass it.
At this point we've covered what [Without a Bundler] section in the Guide meant to convey.
Will differ <a href=https://rustwasm.github.io/wasm-bindgen/examples/synchronous-instantiation.html" target="_blank">[Synchronous Instantiation] for another tutorial.
We'll stick with the default method, asynchronously initializing a module gets all our examples running.
[Converting WebAssembly to JS]. Nothing specific to nobundle, we pass.