Tweak introductory and deployment documentation.

This commit rejiggers some documentation of `wasm-bindgen` in a few
significant ways:

* The main landing page now has text and links to the Game of Life
  tutorial and `wasm-pack`.
* The "whirlwind tour" was deleted as it wasn't really serving any
  purpose that the Game of Life plus the later references weren't already
  serving.
* The "no modules" example was renamed to "without a bundler"
* A dedicated section on "Deployment" was added which replaces the
  previous "No ES Modules" page. This is hopefully more descriptive and
  also prominently mentions the various options for deployment.
This commit is contained in:
Alex Crichton 2019-02-21 11:49:08 -08:00
parent 74a39ce618
commit b71f3374c5
18 changed files with 189 additions and 532 deletions

View File

@ -100,7 +100,7 @@ matrix:
- cargo build -p wasm-bindgen-cli
- ln -snf target/debug/wasm-bindgen $HOME/.cargo/wasm-bindgen
- |
for dir in `ls examples | grep -v README | grep -v asm.js | grep -v raytrace | grep -v no_modules`; do
for dir in `ls examples | grep -v README | grep -v asm.js | grep -v raytrace | grep -v without-a-bundler`; do
(cd examples/$dir &&
ln -fs ../../node_modules . &&
npm run build -- --output-path $HOME/$TRAVIS_BUILD_NUMBER/exbuild/$dir) || exit 1;

View File

@ -72,7 +72,6 @@ members = [
"examples/hello_world",
"examples/import_js",
"examples/julia_set",
"examples/no_modules",
"examples/paint",
"examples/performance",
"examples/raytrace-parallel",
@ -82,6 +81,7 @@ members = [
"examples/wasm2js",
"examples/webaudio",
"examples/webgl",
"examples/without-a-bundler",
"tests/no-std",
]
exclude = ['crates/typescript']

View File

@ -1,20 +0,0 @@
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
</head>
<body>
<!-- this is the JS generated by the `wasm-bindgen` CLI tool -->
<script src='./pkg/no_modules.js'></script>
<script>
window.addEventListener('load', async () => {
// the `wasm_bindgen` global is set to the exports of the Rust module
//
// here we tell bindgen the path to the wasm file so it can run
// initialization and return to us a promise when it's done
// also, we can use 'await' on the returned promise
await wasm_bindgen('./pkg/no_modules_bg.wasm');
});
</script>
</body>
</html>

View File

@ -1,5 +1,5 @@
[package]
name = "no_modules"
name = "without-a-bundler"
version = "0.1.0"
authors = ["The wasm-bindgen Developers"]
edition = "2018"

View File

@ -1,8 +1,8 @@
# Using `--no-modules`
# Without a Bundler
[View documentation for this example online][dox]
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/no-modules.html
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/without-a-bundler.html
You can build the example locally with:

View File

@ -0,0 +1,44 @@
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
</head>
<body>
<!--
This is the JS generated by the `wasm-pack` build command
The script here will define a `wasm_bindgen` global where all
functionality can be accessed such as instantiation and the actual
functions (examples below).
You can customize the name of the file here with the `out-name` CLI flag
to `wasm-bindgen`. You can also customize the name of the global exported
here with the `no-modules-global` flag.
-->
<script src='./pkg/without_a_bundler.js'></script>
<script>
// Import functionality from the wasm module, but note that it's not quite
// ready to be used just yet.
const { add } = wasm_bindgen;
async function run() {
// First up we need to actually load the wasm file, so we use the
// exported global to inform it where the wasm file is located on the
// server, and then we wait on the returned promies to wait for the
// wasm to be loaded.
//
// Note that instead of a string here you can also pass in an instance
// of `WebAssembly.Module` which allows you to compile your own module.
await wasm_bindgen('./pkg/without_a_bundler_bg.wasm');
// And afterwards we can use all the functionality defined in wasm.
const result = add(1, 2);
console.log(`1 + 2 = ${result}`);
if (result !== 3)
throw new Error("wasm addition doesn't work!");
}
run();
</script>
</body>
</html>

View File

@ -1,6 +1,6 @@
use wasm_bindgen::prelude::*;
// Called by our JS entry point to run the example
// Called when the wasm module is instantiated
#[wasm_bindgen(start)]
pub fn main() -> Result<(), JsValue> {
// Use `web_sys`'s global `window` function to get a handle on the global
@ -17,3 +17,8 @@ pub fn main() -> Result<(), JsValue> {
Ok(())
}
#[wasm_bindgen]
pub fn add(a: u32, b: u32) -> u32 {
a + b
}

View File

@ -4,15 +4,11 @@
--------------------------------------------------------------------------------
- [Whirlwind Tour](./whirlwind-tour/introduction.md)
- [Basic Usage](./whirlwind-tour/basic-usage.md)
- [What Just Happened?](./whirlwind-tour/what-just-happened.md)
- [What Else Can We Do?](./whirlwind-tour/what-else-can-we-do.md)
- [Examples](./examples/index.md)
- [Hello, World!](./examples/hello-world.md)
- [Using `console.log`](./examples/console-log.md)
- [Small wasm files](./examples/add.md)
- [Using `--no-modules`](./examples/no-modules.md)
- [Without a Bundler](./examples/without-a-bundler.md)
- [Converting WebAssembly to JS](./examples/wasm2js.md)
- [Importing functions from JS](./examples/import-js.md)
- [Working with `char`](./examples/char.md)
@ -30,11 +26,11 @@
- [Parallel Raytracing](./examples/raytrace.md)
- [web-sys: A TODO MVC App](./examples/todomvc.md)
- [Reference](./reference/index.md)
- [Deployment](./reference/deployment.md)
- [Passing Rust Closures to JS](./reference/passing-rust-closures-to-js.md)
- [Receiving JS Closures in Rust](./reference/receiving-js-closures-in-rust.md)
- [`Promise`s and `Future`s](./reference/js-promises-and-rust-futures.md)
- [Iterating over JS Values](./reference/iterating-over-js-values.md)
- [No ES Modules](./reference/no-esm.md)
- [Arbitrary Data with Serde](./reference/arbitrary-data-with-serde.md)
- [Accessing Properties of Untyped JS Values](./reference/accessing-properties-of-untyped-js-values.md)
- [Working with Duck-Typed Interfaces](./reference/working-with-duck-typed-interfaces.md)

View File

@ -4,13 +4,19 @@ This subsection contains examples of using the `wasm-bindgen`, `js-sys`, and
`web-sys` crates. Each example should have more information about what it's
doing.
The source code for all examples can also be [found online][code] to download an
run locally. Most examples are configured with Webpack/`wasm-pack` and can
These examples all assume familiarity with `wasm-bindgen`, `wasm-pack`, and
building a Rust and WebAssembly project. If you're unfamiliar with these check
out the [Game of Life tutorial][gol] to help you get started.
The source code for all examples can also be [found online][code] to download
and run locally. Most examples are configured with Webpack/`wasm-pack` and can
be built with `npm run serve`. Other examples which don't use Webpack are
accompanied with a `build.sh` showing how to build it.
Note that most examples currently use Webpack to assemble the final output
artifact, but this is not required! You can use the bundler of choice,
`--no-modules`, or native browser ESM support as alternatives to Webpack.
artifact, but this is not required! You can review the [deployment
documentation][deploy] for other options of how to deploy Rust and WebAssembly.
[code]: https://github.com/rustwasm/wasm-bindgen/tree/master/examples
[gol]: https://rustwasm.github.io/book/
[deploy]: ../reference/deployment.html

View File

@ -1,20 +0,0 @@
# Using `--no-modules`
[View full source code][code]
[code]: https://github.com/rustwasm/wasm-bindgen/tree/master/examples/no_modules
This example shows how the `--no-modules` flag can be used load code in a
browser directly (using the same code as the [hello world example][hello]).
Most of the magic happens in `index.html`:
```html
{{#include ../../../examples/no_modules/index.html}}
```
And that's it! It's worth pointing out that if [`#[wasm_bindgen(module =
"...")]` imports are used][mod-imp] then `wasm-bindgen --no-modules` will fail
(as it doesn't know how to import modules).
[hello]: hello-world.html
[mod-imp]: ../reference/attributes/on-js-imports/module.html

View File

@ -0,0 +1,29 @@
# Without a Bundler
[View full source code][code]
[code]: https://github.com/rustwasm/wasm-bindgen/tree/master/examples/without-a-bundler
This example shows how the `--no-modules` flag can be used load code in a
browser directly. For this deployment strategy bundlers like Webpack are not
required. For more information on deployment see the [dedicated
documentation](../reference/deployment.html).
First let's take a look at the code and see how when we're using `--no-modules`
we're not actually losing any functionality!
```rust
{{#include ../../../examples/without-a-bundler/src/lib.rs}}
```
Otherwise the rest of the deployment magic happens in `index.html`:
```html
{{#include ../../../examples/without-a-bundler/index.html}}
```
And that's it! Be sure to read up on the [deployment options] to see what it
means to deploy without a bundler.
[hello]: hello-world.html
[mod-imp]: ../reference/attributes/on-js-imports/module.html

View File

@ -1,15 +1,19 @@
# Introduction
`wasm-bindgen` facilitates high-level interactions between wasm modules and
JavaScript.
This book is about `wasm-bindgen`, a Rust library and CLI tool that facilitate
high-level interactions between wasm modules and JavaScript. The `wasm-bindgen`
tool and crate are only one part of the [Rust and WebAssembly
ecosystem][rustwasm]. If you're not familiar already with `wasm-bindgen` it's
recommended to start by reading the [Game of Life tutorial][gol]. If you're
curious about `wasm-pack`, you can find that [documentation here][wasm-pack].
This project is sort of half polyfill for features like the [host bindings
proposal][host] and half features for empowering high-level interactions between
JS and wasm-compiled code (currently mostly from Rust). More specifically this
project allows JS/wasm to communicate with strings, JS objects, classes, etc, as
opposed to purely integers and floats. Using `wasm-bindgen` for example you can
define a JS class in Rust or take a string from JS or return one. The
functionality is growing as well!
The `wasm-bindgen` tool is sort of half polyfill for features like the [host
bindings proposal][host] and half features for empowering high-level
interactions between JS and wasm-compiled code (currently mostly from Rust).
More specifically this project allows JS/wasm to communicate with strings, JS
objects, classes, etc, as opposed to purely integers and floats. Using
`wasm-bindgen` for example you can define a JS class in Rust or take a string
from JS or return one. The functionality is growing as well!
Currently this tool is Rust-focused but the underlying foundation is
language-independent, and it's hoping that over time as this tool stabilizes
@ -22,10 +26,12 @@ Notable features of this project includes:
* Exporting Rust functionality to JS such as classes, functions, etc.
* Working with rich types like strings, numbers, classes, closures, and objects
rather than simply `u32` and floats.
* Automatically generating TypeScript bindings for Rust code being consumed by
JS.
This project is still relatively new but feedback is of course always
welcome! If you're curious about the design plus even more information about
what this crate can do, check out the [design doc].
With the addition of [`wasm-pack`] you can run the gamut from running Rust on
the web locally, publishing it as part of a larger application, or even
publishing Rust-compiled-to-WebAssembly on NPM!
[host]: https://github.com/WebAssembly/host-bindings
[design doc]: https://rustwasm.github.io/wasm-bindgen/contributing/design/index.html
@ -33,3 +39,6 @@ what this crate can do, check out the [design doc].
[console-log]: https://github.com/rustwasm/wasm-bindgen/tree/master/examples/console_log
[perf-ex]: https://github.com/rustwasm/wasm-bindgen/tree/master/examples/performance
[hello-online]: https://webassembly.studio/?f=gzubao6tg3
[rustwasm]: https://rustwasm.github.io/
[gol]: https://rustwasm.github.io/book/
[wasm-pack]: https://rustwasm.github.io/wasm-pack/book/

View File

@ -0,0 +1,72 @@
# Deploying Rust and WebAssembly
At this point in time deploying Rust and WebAssembly to the web or other
locations unfortunately isn't a trivial task to do. This page hopes to serve
as documentation for the various known options, and as always PRs are welcome
to update this if it's out of date!
## Bundlers
The default output of `wasm-bindgen` assumes a model where the wasm module
itself is natively an ES module. This model, however, not natively implemented
in any JS implementation at this time. As a result, to consume the default
output of `wasm-bindgen` you will need a bundler of some form.
> **Note**: the choice of this default output was done to reflect the trends of
> the JS ecosystem. While tools other than bundlers don't support wasm files as
> native ES modules today they're all very much likely to in the future!
Currently the only known bundler known to be fully compatible with
`wasm-bindgen` is [webpack]. Most [examples] use webpack, and you can check out
the [hello world example online] to see the details of webpack configuration
necessary.
[webpack]: https://webpack.js.org/
[examples]: ../examples/index.html
[hello world example online]: ../examples/hello-world.html
## Without a Bundler
If you're not using a bundler but you're still running code in a web browser,
`wasm-bindgen` still supports this! For this use case you'll want to use the
`--no-modules` flag. You can check out a [full example][nomex] in the
documentation, but the highlights of this output are:
* When using `wasm-pack` you'll pass `--target no-modules`, and when using
`wasm-bindgen` directly you'll pass `--no-modules`.
* The output can natively be included on a web page, and doesn't require any
further postprocessing.
* The `--no-modules` mode is not able to use NPM dependencies nor local JS
snippets (both currently [proposed][rfc1] [features][rfc2])
* You'll want to review the [browser requirements] for `wasm-bindgen` because
no polyfills will be available.
[nomex]: ../examples/without-a-bundler.html
[rfc1]: https://github.com/rustwasm/rfcs/pull/6
[rfc2]: https://github.com/rustwasm/rfcs/pull/8
[browser requirements]: browser-support.html
Despite these limitations almost all code today is compatible with
`--no-modules`, but this area is actively being worked on to improve the
experience so the experience here may be tweaked over time!
## Node.js
If you're deploying WebAssembly into Node.js (perhaps as an alternative to a
native module), then you'll want to pass the `--target nodejs` flag to
`wasm-pack` or the `--nodejs` flag to `wasm-bindgen`.
Like the "without a bundler" strategy, this method of deployment does not
require any further postprocessing. The generated JS shims can be `require`'d
just like any other Node module (even the `*_bg` wasm file can be `require`'d
as it has a JS shim generated as well).
Note that this method requires a version of Node.js with WebAssembly support,
which is currently Node 8 and above.
## NPM
If you'd like to deploy compiled WebAssembly to NPM, then the tool for the job
is [`wasm-pack`]. More information on this coming soon!
[`wasm-pack`]: https://rustwasm.github.io/wasm-pack/book/

View File

@ -1,79 +0,0 @@
# No ES Modules
Explained a bit more in the [internal design](../contributing/design/index.md) section one of the
key foundational principles of `wasm-bindgen` is ES modules. It supports working
without ES modules, however! Not all JS tooling and browsers are ready for ES
modules by default, so it can sometimes be helpful to quickly get up and running
without them to kick the tires and see how `wasm-bindgen` works.
Let's start out with our hello-world example from previous chapters, and you can
also [follow along in the repository][repo].
[repo]: https://github.com/rustwasm/wasm-bindgen/tree/master/examples/no_modules
```rust
#[wasm_bindgen]
extern "C" {
fn alert(msg: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) -> String {
alert(&format!("Hello, {}!", name);
}
```
Like usual, we first compile this to wasm:
```
$ cargo build --target wasm32-unknown-unknown
```
Next, to avoid using ES modules, pass the `--no-modules` option to the
`wasm-bindgen` command:
```
$ wasm-bindgen target/wasm32-unknown-unknown/debug/hello.wasm --no-modules --out-dir .
```
Next up we need to write some HTML to interact with the wasm:
```html
<html>
<body>
<script src='./hello.js'></script>
<script>
wasm_bindgen('./hello_bg.wasm')
.then(() => wasm_bindgen.greet('World'));
</script>
</body>
</html>
```
and that's it! If you open up that web page in a browser (needs to be over HTTP)
then you should see an alert for "Hello, World!".
The `--no-modules` output will not instantiate or compile the wasm module when
included on a web page, instead it just parses and configures the JS bindings
for the wasm-module-to-be. The page is configured with one exported global, in
this case `wasm_bindgen`. The name of this global can be configured with the
`--no-modules-global` option.
The global `wasm_bindgen` is a function that takes one argument: either the path
to the wasm file to fetch or a `WebAssembly.Module`. When invoked `wasm_bindgen`
will return a promise for when the wasm module is ready-to-go. After that all
exported functionality on `wasm_bindgen` will be functional.
In the example above, after calling `wasm_bindgen('./hello_bg.wasm')` we wait
for the wasm module to be fetched and compiled, and afterwards we're invoking
our `greet` export.
Note that exports are available for binding before the wasm module has been
instantiated, for example this would have also worked:
```js
const { greet } = wasm_bindgen;
wasm_bindgen('./hello_bg.wasm')
.then(() => greet('World'));
```

View File

@ -1,184 +0,0 @@
# 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 can 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 --toolchain nightly
$ 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
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
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, define our JS dependencies by creating a `package.json`:
```json
{
"scripts": {
"serve": "webpack-dev-server"
},
"devDependencies": {
"html-webpack-plugin": "^3.2.0",
"webpack": "^4.0.1",
"webpack-cli": "^3.1.1",
"webpack-dev-server": "^3.1.0"
}
}
```
and our `webpack` configuration:
```js
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "index.js",
},
plugins: [
new HtmlWebpackPlugin({
title: "Getting started with WASM"
})
],
mode: "development"
};
```
And finally:
```shell
$ npm install
$ npm run serve
```
If you open [http://localhost:8080](http://localhost:8080) in a browser you should see a `Hello, world!`
dialog pop up!
Notice that `html-webpack-plugin` has generated an HTML page which includes `index.js`.
Finally, you may want to deploy your application to a web server like Apache or NGINX.
For that, simply run:
```shell
$ npx webpack
```
The output will be in the `dist` directory. You can now copy it to the root of your
web server.
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
[hello-online]: https://webassembly.studio/?f=gzubao6tg3

View File

@ -1,9 +0,0 @@
# A Whirlwind Tour of `wasm-bindgen`
What follows is a whirlwind tour of `wasm-bindgen`.
You will learn:
* Setting up your development environment for `wasm-bindgen`
* Importing JavaScript functions and classes into Rust
* Exporting Rust structs and functions to JavaScript

View File

@ -1,159 +0,0 @@
# What Else Can We Do?
Much more! Here's a taste of various features you can use in this project. You
can also [explore this code online](https://webassembly.studio/?f=t61j18noqz):
```rust,ignore
// src/lib.rs
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
// Strings can both be passed in and received
#[wasm_bindgen]
pub fn concat(a: &str, b: &str) -> String {
let mut a = a.to_string();
a.push_str(b);
return a
}
// A struct will show up as a class on the JS side of things
#[wasm_bindgen]
pub struct Foo {
contents: u32,
}
#[wasm_bindgen]
impl Foo {
#[wasm_bindgen(constructor)]
pub fn new() -> Foo {
Foo { contents: 0 }
}
// Methods can be defined with `&mut self` or `&self`, and arguments you
// can pass to a normal free function also all work in methods.
pub fn add(&mut self, amt: u32) -> u32 {
self.contents += amt;
return self.contents
}
// You can also take a limited set of references to other types as well.
pub fn add_other(&mut self, bar: &Bar) {
self.contents += bar.contents;
}
// Ownership can work too!
pub fn consume_other(&mut self, bar: Bar) {
self.contents += bar.contents;
}
}
#[wasm_bindgen]
pub struct Bar {
contents: u32,
opaque: JsValue, // defined in `wasm_bindgen`, imported via prelude
}
#[wasm_bindgen(module = "./index")] // what ES6 module to import from
extern "C" {
fn bar_on_reset(to: &str, opaque: &JsValue);
// We can import classes and annotate functionality on those classes as well
type Awesome;
#[wasm_bindgen(constructor)]
fn new() -> Awesome;
#[wasm_bindgen(method)]
fn get_internal(this: &Awesome) -> u32;
// We can call javascript functions that have a dynamic number of arguments,
// e.g. rust `sum(&[1, 2, 3])` will be called like `sum(1, 2, 3)`
#[wasm_bindgen(variadic)]
fn sum(vals: &[u32]) -> u32;
}
#[wasm_bindgen]
impl Bar {
pub fn from_str(s: &str, opaque: JsValue) -> Bar {
let contents = s.parse().unwrap_or_else(|_| {
Awesome::new().get_internal()
});
Bar { contents, opaque }
}
pub fn reset(&mut self, s: &str) {
if let Ok(n) = s.parse() {
bar_on_reset(s, &self.opaque);
self.contents = n;
}
}
}
```
The generated JS bindings for this invocation of the macro [look like
this][bindings]. You can view them in action like so:
[bindings]: https://gist.github.com/alexcrichton/3d85c505e785fb8ff32e2c1cf9618367
and our corresponding `index.js`:
```js
import { Foo, Bar, concat } from "./js_hello_world";
import { booted } from "./js_hello_world_wasm";
export function bar_on_reset(s, token) {
console.log(token);
console.log(`this instance of bar was reset to ${s}`);
}
function assertEq(a, b) {
if (a !== b)
throw new Error(`${a} != ${b}`);
console.log(`found ${a} === ${b}`);
}
function main() {
assertEq(concat('a', 'b'), 'ab');
// Note that to use `new Foo()` the constructor function must be annotated
// with `#[wasm_bindgen(constructor)]`, otherwise only `Foo.new()` can be used.
// Additionally objects allocated corresponding to Rust structs will need to
// be deallocated on the Rust side of things with an explicit call to `free`.
let foo = new Foo();
assertEq(foo.add(10), 10);
foo.free();
// Pass objects to one another
let foo1 = new Foo();
let bar = Bar.from_str("22", { opaque: 'object' });
foo1.add_other(bar);
// We also don't have to `free` the `bar` variable as this function is
// transferring ownership to `foo1`
bar.reset('34');
foo1.consume_other(bar);
assertEq(foo1.add(2), 22 + 34 + 2);
foo1.free();
alert('all passed!')
}
export class Awesome {
constructor() {
this.internal = 32;
}
get_internal() {
return this.internal;
}
}
export function sum(...args) {
let answer = 0;
for(var i=0; i<args.length; i++) {
answer += args[i];
}
return answer;
}
booted.then(main);
```

View File

@ -1,33 +0,0 @@
# What Just Happened?
Phew! That was a lot of words and a lot ended up happening along the way. There
were two main pieces of magic happening: the `#[wasm_bindgen]` attribute and the
`wasm-bindgen` CLI tool.
**The `#[wasm_bindgen]` attribute**
This attribute, exported from the `wasm-bindgen` crate, is the entrypoint to
exposing Rust functions to JS. This is a procedural macro (hence requiring the
nightly Rust toolchain) which will generate the appropriate shims in Rust to
translate from your type signature to one that JS can interface with. Finally
the attribute also serializes some information to the output artifact which
`wasm-bindgen`-the-tool will discard after it parses.
There's a more thorough explanation below of the various bits and pieces of the
attribute, but it suffices for now to say that you can attach it to free
functions, structs, impl blocks for those structs and `extern "C" { ... }` blocks.
Some Rust features like generics, lifetime parameters, etc, aren't supported on
functions tagged with `#[wasm_bindgen]` right now.
**The `wasm-bindgen` CLI tool**
The next half of what happened here was all in the `wasm-bindgen` tool. This
tool opened up the wasm module that rustc generated and found an encoded
description of what was passed to the `#[wasm_bindgen]` attribute. You can
think of this as the `#[wasm_bindgen]` attribute created a special section of
the output module which `wasm-bindgen` strips and processes.
This information gave `wasm-bindgen` all it needed to know to generate the JS
file that we then imported. The JS file wraps instantiating the underlying wasm
module (aka calling `WebAssembly.instantiate`) and then provides wrappers for
classes/functions within.