mirror of
https://github.com/rustwasm/wasm-bindgen.git
synced 2025-01-05 19:53:55 +03:00
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:
parent
74a39ce618
commit
b71f3374c5
@ -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…
Reference in New Issue
Block a user