mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-16 02:00:51 +00:00
Merge pull request #1285 from alexcrichton/tweak-docs
Tweak introductory and deployment documentation.
This commit is contained in:
commit
5788e7d2c4
@ -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;
|
||||
|
@ -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']
|
||||
|
@ -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>
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "no_modules"
|
||||
name = "without-a-bundler"
|
||||
version = "0.1.0"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
edition = "2018"
|
@ -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:
|
||||
|
44
examples/without-a-bundler/index.html
Normal file
44
examples/without-a-bundler/index.html
Normal 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>
|
@ -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
|
||||
}
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
29
guide/src/examples/without-a-bundler.md
Normal file
29
guide/src/examples/without-a-bundler.md
Normal 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
|
@ -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/
|
||||
|
72
guide/src/reference/deployment.md
Normal file
72
guide/src/reference/deployment.md
Normal 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/
|
@ -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'));
|
||||
```
|
@ -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
|
@ -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
|
@ -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);
|
||||
```
|
@ -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.
|
Loading…
x
Reference in New Issue
Block a user