wasm-bindgen/guide/src/basic-usage.md

179 lines
4.9 KiB
Markdown
Raw Normal View History

# 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`
[rustup]: https://rustup.rs
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:
```shell
$ 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
```shell
$ 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:
```toml
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
```
Next up our actual code! We'll write this in `src/lib.rs`:
```rust,ignore
#![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:
```shell
$ 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!
```shell
$ 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:
```js
const js = import("./js_hello_world");
js.then(js => {
js.greet("World!");
});
```
Note that we're using `import(..)` here because Webpack [doesn't
support][webpack-issue] synchronously importing modules from the main chunk just
yet.
[webpack-issue]: https://github.com/webpack/webpack/issues/6615
Next our JS dependencies by creating a `package.json`:
```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
```js
// 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
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
</head>
<body>
<script src='./index.js'></script>
</body>
</html>
```
And finally:
```shell
$ 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](https://webassembly.studio)
or you can [follow along on GitHub][hello-tree] to see all the files necessary
as well as a script to set it all up.
[hello-tree]: https://github.com/rustwasm/wasm-bindgen/tree/master/examples/hello_world
[hello-readme]: https://github.com/rustwasm/wasm-bindgen/tree/master/examples/hello_world/README.md