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

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.


<-- hello_world
Importing non-browser JS -->