4.9 KiB
Basic Usage
Let's implement the equivalent of "Hello, world!" for this crate.
Note: Currently this projects uses nightly Rust which you can acquire through rustup and configure with
rustup default nightly
If you'd like you dive [straight into an online example][hello-online], but if you'd prefer to follow along in your own console let's install the tools we need:
$ rustup target add wasm32-unknown-unknown
$ cargo +nightly install wasm-bindgen-cli
The first command here installs the wasm target so you can compile to it, and
the latter will install the wasm-bindgen
CLI tool we'll be using later.
Next up let's make our project
$ cargo +nightly new js-hello-world --lib
Now let's add a dependency on this project inside Cargo.toml
as well as
configuring our build output:
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
Next up our actual code! We'll write this in src/lib.rs
:
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
And that's it! If we were to write the greet
function naively without the
#[wasm_bindgen]
attribute then JS wouldn't be able to communicate with the
types like str
, so slapping a #[wasm_bindgen]
on the function and the import
of alert
ensures that the right shims are generated.
Next up let's build our project:
$ cargo +nightly build --target wasm32-unknown-unknown
After this you'll have a wasm file at
target/wasm32-unknown-unknown/debug/js_hello_world.wasm
. Don't be alarmed at
the size, this is an unoptimized program!
Now that we've generated the wasm module it's time to run the bindgen tool itself! This tool will postprocess the wasm file rustc generated, generating a new wasm file and a set of JS bindings as well. Let's invoke it!
$ wasm-bindgen target/wasm32-unknown-unknown/debug/js_hello_world.wasm \
--out-dir .
This is the main point where the magic happens. The js_hello_world.wasm
file
emitted by rustc contains descriptors of how to communicate via richer types
than wasm currently supports. The wasm-bindgen
tool will interpret this
information, emitting a replacement module for the wasm file.
The previous js_hello_world.wasm
file is interpreted as if it were an ES6
module. The js_hello_world.js
file emitted by wasm-bindgen
should have the
intended interface of the wasm file, notably with rich types like strings,
classes, etc.
The wasm-bindgen
tool also emits a few other files needed to implement this
module. For example js_hello_world_bg.wasm
is the original wasm file but
postprocessed a bit. It's intended that the js_hello_world_bg.wasm
file,
like before, acts like an ES6 module.
At this point you'll probably plug these files into a larger build system.
Files emitted by wasm-bindgen
act like normal ES6 modules (one just happens to
be wasm). As of the time of this writing there's unfortunately not a lot of
tools that natively do this, but Webpack's 4.0 beta release has native wasm
support!. Let's take a look at that and see how it works.
First create an index.js
file:
const js = import("./js_hello_world");
js.then(js => {
js.greet("World!");
});
Note that we're using import(..)
here because Webpack doesn't
support synchronously importing modules from the main chunk just
yet.
Next our JS dependencies by creating a package.json
:
{
"scripts": {
"serve": "webpack-dev-server"
},
"devDependencies": {
"webpack": "^4.0.1",
"webpack-cli": "^2.0.10",
"webpack-dev-server": "^3.1.0"
}
}
and our webpack configuration
// webpack.config.js
const path = require('path');
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "index.js",
},
mode: "development"
};
Our corresponding index.html
:
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
</head>
<body>
<script src='./index.js'></script>
</body>
</html>
And finally:
$ npm run serve
If you open https://localhost:8080 in a browser you should see a Hello, world!
dialog pop up!
If that was all a bit much, no worries! You can [execute this code online][hello-online] thanks to WebAssembly Studio or you can follow along on GitHub to see all the files necessary as well as a script to set it all up.