guide: Add a user-facing web-sys section

This commit is contained in:
Nick Fitzgerald 2018-09-10 17:51:44 -07:00
parent 723ed6e856
commit 86796f8a03
12 changed files with 244 additions and 93 deletions

View File

@ -50,6 +50,18 @@
--------------------------------------------------------------------------------
- [`web-sys`](./web-sys/index.md)
- [Using `web-sys`](./web-sys/using-web-sys.md)
- [Cargo Features](./web-sys/cargo-features.md)
- [Function Overloads](./web-sys/function-overloads.md)
- [Type Translations](./web-sys/type-translations.md)
- [Examples](./web-sys/examples/index.md)
- [The `fetch` API](./web-sys/examples/fetch.md)
- [2D Canvas](./web-sys/examples/2d-canvas.md)
- [WebAudio](./web-sys/examples/web-audio.md)
--------------------------------------------------------------------------------
- [Contributing](./contributing/index.md)
- [Testing](./contributing/testing.md)
- [Internal Design](./contributing/design/index.md)

View File

@ -8,96 +8,3 @@ using `wasm-bindgen`'s WebIDL frontend and the WebIDL interface definitions for
Web APIs. This means that `web-sys` isn't always the most ergonomic crate to
use, but it's intended to provide verified and correct bindings to the web
platform, and then better interfaces can be iterated on crates.io!
### Using `web-sys`
Let's say you want to use an API defined on the web. Chances are this API is
defined in `web-sys`, so let's go through some steps necessary to use it!
First up, search the [api documentation][api] for your API. For example if
we're looking for JS's [`fetch`][jsfetch] API we'd start out by [searching for
`fetch`][search-fetch]. The first thing you'll probably notice is that there's
no function called `fetch`! Fear not, though, as the API exists in multiple
forms:
* [`Window::fetch_with_str`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Window.html#method.fetch_with_str)
* [`Window::fetch_with_request`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Window.html#method.fetch_with_request)
* [`Window::fetch_with_str_and_init`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/str_and_inituct.Window.html#method.fetch_with_str_and_init)
* [`Window::fetch_with_request_and_init`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Window.html#method.fetch_with_request_and_init)
What's happening here is that the [`fetch` function][fetchfn] actually supports
multiple signatures of arguments, and we've taken the WebIDL definition for this
function and expanded it to unique signatures in Rust (as Rust doesn't have
function name overloading).
When an API is selected it should have documentation pointing at MDN indicating
what web API its binding. This is often a great way to double check arguments
and such as well, MDN is a great resource! You'll also notice in the
documentation that the API may require some `web-sys` Cargo features to be
activated. For example [`fetch_with_str`] requires the `Window` feature to be
activated. In general an API needs features corresponding to all the types
you'll find in the signature to be activated.
To load up this API let's depend on `web-sys`:
```toml
[dependencies]
wasm-bindgen = "0.2"
web-sys = { version = "0.1", features = ['Window'] }
# Or optionally,
# [target.wasm32-unknown-unknown.dependencies]
# ...
```
> **Note**: Currently `web-sys` is not available on crates.io so you'll also
> need to do this in your manifest:
>
> ```toml
> [patch.crates-io]
> web-sys = { git = 'https://github.com/rustwasm/wasm-bindgen' }
> wasm-bindgen = { git = 'https://github.com/rustwasm/wasm-bindgen' }
> ```
And next up we can use the API like so:
```rust
extern crate web_sys;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
use web_sys::Window;
#[wasm_bindgen]
pub fn run() {
let promise = Window::fetch_with_str("http://example.com/");
// ...
}
```
and you should be good to go!
### Type translations in `web-sys`
Most of the types specified in WebIDL have relatively straightforward
translations into `web-sys`, but it's worth calling out a few in particular:
* `BufferSource` and `ArrayBufferView` - these two types show up in a number of
APIs that generally deal with a buffer of bytes. We bind them in `web-sys`
with two different types, `Object` and `&mut [u8]`. Using `Object` allows
passing in arbitrary JS values which represent a view of bytes (like any typed
array object), and `&mut [u8]` allows using a raw slice in Rust. Unfortunately
we must pessimistically assume that JS will modify all slices as we don't
currently have information of whether they're modified or not.
* Callbacks are all represented as `js_sys::Function`. This means that all
callbacks going through `web-sys` are a raw JS value. You can work with this
by either juggling actual `js_sys::Function` instances or you can create a
`Closure<FnMut(...)>`, extract the underlying `JsValue` with `as_ref`, and
then use `JsCast::unchecked_ref` to convert it to a `js_sys::Function`.
[api]: https://rustwasm.github.io/wasm-bindgen/api/web_sys/
[jsfetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
[search-fetch]: https://rustwasm.github.io/wasm-bindgen/api/web_sys/?search=fetch
[fetchfn]: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
[`fetch_with_str`]: https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Window.html#method.fetch_with_str

View File

@ -0,0 +1,15 @@
# Cargo Features in `web-sys`
To keep `web-sys` building as fast as possible, there is a cargo feature for
every type defined in `web-sys`. To access that type, you must enable its
feature. To access a method, you must enable the feature for its `self` type and
the features for each of its argument types. In the [API documentation][], every
method lists the features that are required to enable it.
For example, [the `WebGlRenderingContext::compile_shader` function][compile_shader] requires these features:
* `WebGlRenderingContext`, because that is the method's `self` type
* `WebGlShader`, because it takes an argument of that type
[API documentation]: https://rustwasm.github.io/wasm-bindgen/api/web_sys
[compile_shader]: https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.WebGlRenderingContext.html#method.compile_shader

View File

@ -0,0 +1,29 @@
# 2D Canvas
Drawing a smiley face with the 2D canvas API. This is a port of part of [this
MDN
tutorial](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes#Moving_the_pen)
to `web-sys`.
[See the full source at
`wasm-bindgen/examples/canvas`.](https://github.com/rustwasm/wasm-bindgen/tree/master/examples/canvas)
![A smiley face](./2d-canvas.png)
## `Cargo.toml`
The `Cargo.toml` enables features necessary to query the DOM and work with 2D
canvas.
```toml
{{#include ../../../../examples/canvas/Cargo.toml}}
```
## `src/lib.rs`
Gets the `<canvas>` element, creates a 2D rendering context, and draws the
smiley face.
```rust
{{#include ../../../../examples/canvas/src/lib.rs}}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,23 @@
# The `fetch` API
This example uses the `fetch` API to make an HTTP request to the GitHub API and
then parses the resulting JSON.
[See the full source at
`wasm-bindgen/examples/fetch`.](https://github.com/rustwasm/wasm-bindgen/tree/master/examples/fetch)
## `Cargo.toml`
The `Cargo.toml` enables a number of features related to the `fetch` API and
types used: `Headers`, `Request`, etc. It also enables `wasm-bindgen`'s `serde`
support.
```toml
{{#include ../../../../examples/fetch/Cargo.toml}}
```
## `src/lib.rs`
```rust
{{#include ../../../../examples/fetch/src/lib.rs}}
```

View File

@ -0,0 +1,3 @@
# Examples of using `web-sys`
This subsection contains examples of using the `web-sys` crate.

View File

@ -0,0 +1,36 @@
# WebAudio
This example creates an [FM
oscillator](https://en.wikipedia.org/wiki/Frequency_modulation_synthesis) using
the [WebAudio
API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API) and
`web-sys`.
[See the full source at
`wasm-bindgen/examples/webaudio`.](https://github.com/rustwasm/wasm-bindgen/tree/master/examples/webaudio)
## `Cargo.toml`
The `Cargo.toml` enables the types needed to use the relevant bits of the
WebAudio API.
```toml
{{#include ../../../../examples/webaudio/Cargo.toml}}
```
## `src/lib.rs`
The Rust code implements the FM oscillator.
```rust
{{#include ../../../../examples/webaudio/src/lib.rs}}
```
## `index.js`
A small bit of JavaScript glues the rust module to input widgets and translates
events into calls into wasm code.
```js
{{#include ../../../../examples/webaudio/index.js}}
```

View File

@ -0,0 +1,20 @@
# Function Overloads
Many Web APIs are overloaded to take different types of arguments or to skip
arguments completely. `web-sys` contains multiple bindings for these functions
that each specialize to a particular overload and set of argument types.
For example, [the `fetch` API][mdn-fetch] can be given a URL string, or a
`Request` object, and it might also optionally be given a `RequestInit` options
object. Therefore, we end up with these `web-sys` functions that all bind to the
`window.fetch` function:
* [`Window::fetch_with_str`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Window.html#method.fetch_with_str)
* [`Window::fetch_with_request`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Window.html#method.fetch_with_request)
* [`Window::fetch_with_str_and_init`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/str_and_inituct.Window.html#method.fetch_with_str_and_init)
* [`Window::fetch_with_request_and_init`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Window.html#method.fetch_with_request_and_init)
Note that different overloads can use different interfaces, and therefore can
require different sets of cargo features to be enabled.
[mdn-fetch]: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch

View File

@ -0,0 +1,23 @@
# The `web-sys` Crate
The `web-sys` crate provides raw `wasm-bindgen` imports for all of the Web's
APIs. This includes:
* `window.fetch`
* `Node.prototype.appendChild`
* WebGL
* WebAudio
* and many more!
It's sort of like the `libc` crate, but for the Web.
It does *not* include the JavaScript APIs that are guaranteed to exist in all
standards-compliant ECMAScript environments, such as `Array`, `Date`, and
`eval`. Bindings for these APIs can be found in [the `js-sys` crate][js-sys].
## API Documentation
[**Read the `web-sys` API documentation here!**][api]
[api]: https://rustwasm.github.io/wasm-bindgen/api/web_sys/
[js-sys]: https://crates.io/crates/js-sys

View File

@ -0,0 +1,22 @@
# Type Translations in `web-sys`
Most of the types specified in [WebIDL (the interface definition language for
all Web APIs)][webidl] have relatively straightforward translations into
`web-sys`, but it's worth calling out a few in particular:
* `BufferSource` and `ArrayBufferView` - these two types show up in a number of
APIs that generally deal with a buffer of bytes. We bind them in `web-sys`
with two different types, `js_sys::Object` and `&mut [u8]`. Using
`js_sys::Object` allows passing in arbitrary JS values which represent a view
of bytes (like any typed array object), and `&mut [u8]` allows using a raw
slice in Rust. Unfortunately we must pessimistically assume that JS will
modify all slices as we don't currently have information of whether they're
modified or not.
* Callbacks are all represented as `js_sys::Function`. This means that all
callbacks going through `web-sys` are a raw JS value. You can work with this
by either juggling actual `js_sys::Function` instances or you can create a
`Closure<FnMut(...)>`, extract the underlying `JsValue` with `as_ref`, and
then use `JsCast::unchecked_ref` to convert it to a `js_sys::Function`.
[webidl]: https://heycam.github.io/webidl/

View File

@ -0,0 +1,61 @@
# Using `web-sys`
## Add `web-sys` as a dependency to your `Cargo.toml`
***Note:** `web-sys` is not available on crates.io yet, so you'll need to depend
on the git version of it, and of `wasm-bindgen`:*
```toml
[dependencies]
wasm-bindgen = { git = "https://github.com/rustwasm/wasm-bindgen" }
web-sys = {
git = "https://github.com/rustwasm/wasm-bindgen",
features = [
]
}
```
## Enable the cargo features for the APIs you're using
To keep build times super speedy, [`web-sys` gates each Web interface behind a
cargo feature](./cargo-features.html). Find the type or method you want to use
in the [API documentation][api]; it will list the features that must be enabled
to access that API.
For example, if we're looking for [the `window.resizeTo`
function][js-resize-to], we would [search for `resizeTo` in the API
documentation][search-resize-to]. We would find [the
`web_sys::Window::resize_to` function][rust-resize-to], which requires the
`Window` feature. To get access to that function, we enable the `Window` feature
in `Cargo.toml`:
```toml
web-sys = {
git = "https://github.com/rustwasm/wasm-bindgen",
features = [
"Window",
]
}
```
## Call the method!
```rust
extern crate web_sys;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
use web_sys::Window;
#[wasm_bindgen]
pub fn make_the_window_small() {
// Resize the window to 500px by 500px.
Window::resize_to(500, 500)
.expect("could not resize the window");
}
```
[api]: https://rustwasm.github.io/wasm-bindgen/api/web_sys/
[js-resize-to]: https://developer.mozilla.org/en-US/docs/Web/API/window/resizeTo
[search-resize-to]: https://rustwasm.github.io/wasm-bindgen/api/web_sys/?search=resizeTo
[rust-resize-to]: https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Window.html#method.resize_to