Hello, World!

    Make sure you have followed the setup instructions before beginning.

    The project template comes pre-configured with sane defaults, so you can quicklybuild, integrate, and package your code for the Web.

    Clone the project template with this command:

    This should prompt you for the new project's name. We will use"wasm-game-of-life".

    What's Inside

    Enter the new wasm-game-of-life project

    1. cd wasm-game-of-life

    and let's take a look at its contents:

    1. wasm-game-of-life/
    2. ├── Cargo.toml
    3. ├── LICENSE_APACHE
    4. ├── LICENSE_MIT
    5. ├── README.md
    6. └── src
    7. ├── lib.rs
    8. └── utils.rs

    Let's take a look at a couple of these files in detail.

    The Cargo.toml file specifies dependencies and metadata for cargo, Rust'spackage manager and build tool. This one comes pre-configured with awasm-bindgen dependency, a few optional dependencies we will dig into later,and the crate-type properly initialized for generating .wasm libraries.

    wasm-game-of-life/src/lib.rs

    The src/lib.rs file is the root of the Rust crate that we are compiling toWebAssembly. It uses wasm-bindgen to interface with JavaScript. It imports thewindow.alert JavaScript function, and exports the greet Rust function, whichalerts a greeting message.

    1. # #![allow(unused_variables)]
    2. #fn main() {
    3. mod utils;
    4. use wasm_bindgen::prelude::*;
    5. // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
    6. // allocator.
    7. #[cfg(feature = "wee_alloc")]
    8. #[global_allocator]
    9. static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
    10. #[wasm_bindgen]
    11. extern {
    12. fn alert(s: &str);
    13. }
    14. #[wasm_bindgen]
    15. pub fn greet() {
    16. alert("Hello, wasm-game-of-life!");
    17. }
    18. #}

    wasm-game-of-life/src/utils.rs

    The src/utils.rs module provides common utilities to make working with Rustcompiled to WebAssembly easier. We will take a look at some of these utilitiesin more detail later in the tutorial, such as when we look at debugging our wasmcode, but we can ignore this file for now.

    We use wasm-pack to orchestrate the following build steps:

    • Ensure that we have Rust 1.30 or newer and the wasm32-unknown-unknowntarget installed via rustup,
    • Compile our Rust sources into a WebAssembly .wasm binary via cargo,
    • Use wasm-bindgen to generate the JavaScript API for using our Rust-generatedWebAssembly.

    To do all of that, run this command inside the project directory:

    1. wasm-pack build

    When the build has completed, we can find its artifacts in the pkg directory,and it should have these contents:

    1. pkg/
    2. ├── package.json
    3. ├── README.md
    4. ├── wasm_game_of_life_bg.wasm
    5. ├── wasm_game_of_life.d.ts

    wasm-game-of-life/pkg/wasm_game_of_life_bg.wasm

    The .wasm file is the WebAssembly binary that is generated by the Rustcompiler from our Rust sources. It contains the compiled-to-wasm versions of allof our Rust functions and data. For example, it has an exported "greet"function.

    The .js file is generated by wasm-bindgen and contains JavaScript glue forimporting DOM and JavaScript functions into Rust and exposing a nice API to theWebAssembly functions to JavaScript. For example, there is a JavaScript greetfunction that wraps the greet function exported from the WebAssemblymodule. Right now, this glue isn't doing much, but when we start passing moreinteresting values back and forth between wasm and JavaScript, it will helpshepherd those values across the boundary.

    wasm-game-of-life/pkg/wasm_game_of_life.d.ts

    The .d.ts file contains type declarations for the JavaScriptglue. If you are using TypeScript, you can have your calls into WebAssemblyfunctions type checked, and your IDE can provide autocompletions andsuggestions! If you aren't using TypeScript, you can safely ignore this file.

    1. export function greet(): void;

    wasm-game-of-life/pkg/package.json

    This is used by npm and JavaScript bundlersto determine dependencies across packages, package names, versions, and a bunchof other stuff. It helps us integrate with JavaScript tooling and allows us topublish our package to npm.

    1. {
    2. "name": "wasm-game-of-life",
    3. "collaborators": [
    4. "Your Name <your.email@example.com>"
    5. ],
    6. "description": null,
    7. "version": "0.1.0",
    8. "license": null,
    9. "repository": null,
    10. "files": [
    11. "wasm_game_of_life_bg.wasm",
    12. "wasm_game_of_life.d.ts"
    13. ],
    14. "main": "wasm_game_of_life.js",
    15. "types": "wasm_game_of_life.d.ts"
    16. }

    Putting it into a Web Page

    To take our wasm-game-of-life package and use it in a Web page, we use .

    Run this command within the wasm-game-of-life directory:

    1. npm init wasm-app www

    Here's what our new wasm-game-of-life/www subdirectory contains:

    1. wasm-game-of-life/www/
    2. ├── bootstrap.js
    3. ├── index.html
    4. ├── LICENSE-APACHE
    5. ├── LICENSE-MIT
    6. ├── package.json
    7. ├── README.md
    8. └── webpack.config.js

    Once again, let's take a closer look at some of these files.

    wasm-game-of-life/www/package.json

    This package.json comes pre-configured with webpack and webpack-dev-serverdependencies, as well as a dependency on hello-wasm-pack, which is a versionof the initial wasm-pack-template package that has been published to npm.

    This file configures webpack and its local development server. It comespre-configured, and you shouldn't have to tweak this at all to get webpack andits local development server working.

    wasm-game-of-life/www/index.html

    This is the root HTML file for the Web page. It doesn't do much other thanload bootstrap.js, which is a very thin wrapper around index.js.

    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <meta charset="utf-8">
    5. <title>Hello wasm-pack!</title>
    6. </head>
    7. <body>
    8. <script src="./bootstrap.js"></script>
    9. </body>
    10. </html>

    wasm-game-of-life/www/index.js

    The is the main entry point for our Web page's JavaScript. It importsthe hello-wasm-pack npm package, which contains the defaultwasm-pack-template's compiled WebAssembly and JavaScript glue, then it callshello-wasm-pack's greet function.

    1. import * as wasm from "hello-wasm-pack";
    2. wasm.greet();

    Install the dependencies

    First, ensure that the local development server and its dependencies areinstalled by running npm install within the wasm-game-of-life/wwwsubdirectory:

    Rather than use the hello-wasm-pack package from npm, we want to use our localwasm-game-of-life package instead. This will allow us to incrementally developour Game of Life program.

    Open up wasm-game-of-life/www/package.json and next to "devDependencies", add the "dependencies" field,including a "wasm-game-of-life": "file:../pkg" entry:

    1. {
    2. // ...
    3. "dependencies": { // Add this three lines block!
    4. "wasm-game-of-life": "file:../pkg"
    5. },
    6. "devDependencies": {
    7. //...
    8. }
    9. }

    Next, modify wasm-game-of-life/www/index.js to import wasm-game-of-lifeinstead of the hello-wasm-pack package:

    1. import * as wasm from "wasm-game-of-life";
    2. wasm.greet();

    Since we declared a new dependency, we need to install it:

    1. npm install

    Our Web page is now ready to be served locally!

    Next, open a new terminal for the development server. Running the server in anew terminal lets us leave it running in the background, and doesn't block usfrom running other commands in the meantime. In the new terminal, run thiscommand from within the wasm-game-of-life/www directory:

    1. npm run start

    Navigate your Web browser to http://localhost:8080/and you should be greeted with an alert message:

    Anytime you make changes and want them reflected onhttp://localhost:8080/, just re-run the wasm-pack build command within the wasm-game-of-life directory.

    Exercises

    • Modify the greet function in wasm-game-of-life/src/lib.rs to take a name: &str parameter that customizes the alerted message, and pass your name to thegreet function from inside wasm-game-of-life/www/index.js. Rebuild the.wasm binary with wasm-pack build, then refreshhttp://localhost:8080/ in your Web browser and youshould see a customized greeting!

    Answer

    New version of the greet function in wasm-game-of-life/src/lib.rs:

    1. # #![allow(unused_variables)]
    2. #fn main() {
    3. #[wasm_bindgen]
    4. pub fn greet(name: &str) {
    5. alert(&format!("Hello, {}!", name));
    6. }
    7. #}

    New invocation of greet in wasm-game-of-life/www/index.js: