mirror of
https://github.com/rustwasm/wasm-bindgen.git
synced 2024-12-28 12:32:37 +03:00
Merge pull request #808 from fitzgen/web-sys-in-the-guide
web-sys gets its own section in the guide
This commit is contained in:
commit
1d2d397f55
@ -3,6 +3,8 @@ name = "web-sys"
|
||||
version = "0.1.0"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
readme = "./README.md"
|
||||
homepage = "https://rustwasm.github.io/wasm-bindgen/web-sys/index.html"
|
||||
documentation = "https://rustwasm.github.io/wasm-bindgen/api/web_sys/"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
@ -1,10 +1,10 @@
|
||||
# `web-sys`
|
||||
|
||||
[Documentation](https://rustwasm.github.io/wasm-bindgen/api/web_sys/)
|
||||
|
||||
Raw bindings to Web APIs for projects using `wasm-bindgen`.
|
||||
|
||||
The book: https://rustwasm.github.io/wasm-bindgen/web-sys.html
|
||||
* [The `web-sys` section of the `wasm-bindgen`
|
||||
guide](https://rustwasm.github.io/wasm-bindgen/web-sys/index.html)
|
||||
* [API Documentation](https://rustwasm.github.io/wasm-bindgen/api/web_sys/)
|
||||
|
||||
## Crate features
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "fetch"
|
||||
version = "0.1.0"
|
||||
authors = ["Andrew Chin <achin@eminence32.net>"]
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@ -1,21 +1,23 @@
|
||||
extern crate wasm_bindgen;
|
||||
extern crate js_sys;
|
||||
extern crate web_sys;
|
||||
extern crate wasm_bindgen_futures;
|
||||
extern crate futures;
|
||||
extern crate js_sys;
|
||||
extern crate wasm_bindgen;
|
||||
extern crate wasm_bindgen_futures;
|
||||
extern crate web_sys;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
use futures::{future, Future};
|
||||
use js_sys::Promise;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use js_sys::Promise;
|
||||
use web_sys::{Request, RequestInit, RequestMode, Response, Window};
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use futures::{future, Future};
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use web_sys::{Request, RequestInit, RequestMode, Response, Window};
|
||||
|
||||
// A struct to hold some data from the github Branch API.
|
||||
// Note how we don't have to define every member -- serde will ignore extra data when deserializing
|
||||
/// A struct to hold some data from the github Branch API.
|
||||
///
|
||||
/// Note how we don't have to define every member -- serde will ignore extra
|
||||
/// data when deserializing
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Branch {
|
||||
pub name: String,
|
||||
@ -42,37 +44,38 @@ pub struct Signature {
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run() -> Promise {
|
||||
let mut request_options = RequestInit::new();
|
||||
request_options.method("GET");
|
||||
request_options.mode(RequestMode::Cors);
|
||||
let mut opts = RequestInit::new();
|
||||
opts.method("GET");
|
||||
opts.mode(RequestMode::Cors);
|
||||
|
||||
let req = Request::new_with_str_and_init("https://api.github.com/repos/rustwasm/wasm-bindgen/branches/master", &request_options).unwrap();
|
||||
let request = Request::new_with_str_and_init(
|
||||
"https://api.github.com/repos/rustwasm/wasm-bindgen/branches/master",
|
||||
&opts,
|
||||
).unwrap();
|
||||
|
||||
// the RequestInit struct will eventually support setting headers, but that's missing right now
|
||||
req.headers().set("Accept", "application/vnd.github.v3+json").unwrap();
|
||||
request.headers()
|
||||
.set("Accept", "application/vnd.github.v3+json")
|
||||
.unwrap();
|
||||
|
||||
let req_promise = Window::fetch_with_request(&req);
|
||||
let request_promise = Window::fetch_with_request(&request);
|
||||
|
||||
let to_return = JsFuture::from(req_promise).and_then(|resp_value| {
|
||||
// resp_value is a Response object
|
||||
assert!(resp_value.is_instance_of::<Response>());
|
||||
let resp: Response = resp_value.dyn_into().unwrap();
|
||||
let future = JsFuture::from(request_promise)
|
||||
.and_then(|resp_value| {
|
||||
// `resp_value` is a `Response` object.
|
||||
assert!(resp_value.is_instance_of::<Response>());
|
||||
let resp: Response = resp_value.dyn_into().unwrap();
|
||||
resp.json()
|
||||
}).and_then(|json_value: Promise| {
|
||||
// Convert this other `Promise` into a rust `Future`.
|
||||
JsFuture::from(json_value)
|
||||
}).and_then(|json| {
|
||||
// Use serde to parse the JSON into a struct.
|
||||
let branch_info: Branch = json.into_serde().unwrap();
|
||||
|
||||
resp.json()
|
||||
// Send the `Branch` struct back to JS as an `Object`.
|
||||
future::ok(JsValue::from_serde(&branch_info).unwrap())
|
||||
});
|
||||
|
||||
|
||||
}).and_then(|json_value: Promise| {
|
||||
// convert this other promise into a rust Future
|
||||
JsFuture::from(json_value)
|
||||
}).and_then(|json| {
|
||||
// Use serde to parse this into a struct
|
||||
let branch_info: Branch = json.into_serde().unwrap();
|
||||
|
||||
// Send the Branch struct back to javascript as an object
|
||||
future::ok(JsValue::from_serde(&branch_info).unwrap())
|
||||
});
|
||||
|
||||
// Convert this rust future back into a javascript promise.
|
||||
// Return it to javascript so that it can be driven to completion.
|
||||
future_to_promise(to_return)
|
||||
// Convert this Rust `Future` back into a JS `Promise`.
|
||||
future_to_promise(future)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "webaudio"
|
||||
version = "0.1.0"
|
||||
authors = ["Andrew Chin <achin@eminence32.net>"]
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@ -3,16 +3,9 @@
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
// Global variable, so a user can play with it via the JS console
|
||||
var fm;
|
||||
function play() {
|
||||
console.log("Rust module not loaded yet!");
|
||||
}
|
||||
</script>
|
||||
<script src='./index.js'></script>
|
||||
|
||||
<input type="button" value="Click me first to turn on audio" onclick="javascript: play();" />
|
||||
<input id="play" type="button" value="Click me first to turn on audio"/>
|
||||
(headphone users, please make sure your volume is not too loud!)
|
||||
|
||||
<div>
|
||||
|
@ -1,40 +1,35 @@
|
||||
const rust = import('./webaudio');
|
||||
import('./webaudio').then(rust_module => {
|
||||
let fm = null;
|
||||
|
||||
const play_button = document.getElementById("play");
|
||||
play_button.addEventListener("click", event => {
|
||||
if (fm === null) {
|
||||
fm = new rust_module.FmOsc();
|
||||
fm.set_note(50);
|
||||
fm.set_fm_frequency(0);
|
||||
fm.set_fm_amount(0);
|
||||
fm.set_gain(0.8);
|
||||
}
|
||||
});
|
||||
|
||||
// Most browsers don't let WebAudio autoplay without some interaction from the user. So once the module is loaded,
|
||||
// it's passed to this function which will set up the UI elements for the user to interact with
|
||||
function setup(rust_module) {
|
||||
play = function() {
|
||||
console.log("About to create some music!");
|
||||
fm = new rust_module.FmOsc();
|
||||
const primary_slider = document.getElementById("primary_input");
|
||||
primary_slider.addEventListener("input", event => {
|
||||
if (fm) {
|
||||
fm.set_note(event.target.value);
|
||||
}
|
||||
});
|
||||
|
||||
fm.set_note(50);
|
||||
fm.set_fm_frequency(0);
|
||||
fm.set_fm_amount(0);
|
||||
fm.set_gain(0.8);
|
||||
const fm_freq = document.getElementById("fm_freq");
|
||||
fm_freq.addEventListener("input", event => {
|
||||
if (fm) {
|
||||
fm.set_fm_frequency(event.target.value);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// create some UI elements
|
||||
const primary_slider = document.getElementById("primary_input");
|
||||
primary_slider.oninput = (e) => {
|
||||
fm.set_note(e.target.value);
|
||||
};
|
||||
|
||||
const fm_freq = document.getElementById("fm_freq");
|
||||
fm_freq.oninput = (e) => {
|
||||
fm.set_fm_frequency(e.target.value);
|
||||
};
|
||||
|
||||
const fm_amount = document.getElementById("fm_amount");
|
||||
fm_amount.oninput = (e) => {
|
||||
fm.set_fm_amount(e.target.value);
|
||||
};
|
||||
|
||||
console.log("Ready! Press the play button!");
|
||||
}
|
||||
|
||||
|
||||
rust.then(m => {
|
||||
setup(m);
|
||||
const fm_amount = document.getElementById("fm_amount");
|
||||
fm_amount.addEventListener("input", event => {
|
||||
if (fm) {
|
||||
fm.set_fm_amount(event.target.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -4,6 +4,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"webpack": "^4.16.5",
|
||||
"webpack-serve": "^2.0.2"
|
||||
"webpack-cli": "^2.0.10",
|
||||
"webpack-dev-server": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ extern crate wasm_bindgen;
|
||||
extern crate web_sys;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::{AudioContext, BaseAudioContext, AudioNode, AudioScheduledSourceNode, OscillatorType};
|
||||
use web_sys::{
|
||||
AudioContext, AudioNode, AudioScheduledSourceNode, BaseAudioContext, OscillatorType,
|
||||
};
|
||||
|
||||
/// Converts a midi note to frequency
|
||||
///
|
||||
@ -32,16 +34,12 @@ pub struct FmOsc {
|
||||
fm_freq_ratio: f32,
|
||||
|
||||
fm_gain_ratio: f32,
|
||||
|
||||
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl FmOsc {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> FmOsc {
|
||||
// TODO, how to throw from a constructor?
|
||||
|
||||
let ctx = web_sys::AudioContext::new().unwrap();
|
||||
let primary;
|
||||
let fm_osc;
|
||||
@ -51,14 +49,14 @@ impl FmOsc {
|
||||
{
|
||||
let base: &BaseAudioContext = ctx.as_ref();
|
||||
|
||||
// create our web audio objects
|
||||
// Create our web audio objects.
|
||||
primary = base.create_oscillator().unwrap();
|
||||
fm_osc = base.create_oscillator().unwrap();
|
||||
gain = base.create_gain().unwrap();
|
||||
fm_gain = base.create_gain().unwrap();
|
||||
}
|
||||
|
||||
// some initial settings:
|
||||
// Some initial settings:
|
||||
primary.set_type(OscillatorType::Sine);
|
||||
primary.frequency().set_value(440.0); // A4 note
|
||||
gain.gain().set_value(0.0); // starts muted
|
||||
@ -66,7 +64,6 @@ impl FmOsc {
|
||||
fm_osc.set_type(OscillatorType::Sine);
|
||||
fm_osc.frequency().set_value(0.0);
|
||||
|
||||
|
||||
// Create base class references:
|
||||
{
|
||||
let primary_node: &AudioNode = primary.as_ref();
|
||||
@ -77,26 +74,36 @@ impl FmOsc {
|
||||
let destination = base.destination();
|
||||
let destination_node: &AudioNode = destination.as_ref();
|
||||
|
||||
// Connect the nodes up!
|
||||
|
||||
// connect them up:
|
||||
|
||||
// The primary oscillator is routed through the gain node, so that it can control the overall output volume
|
||||
// The primary oscillator is routed through the gain node, so that
|
||||
// it can control the overall output volume.
|
||||
primary_node.connect_with_audio_node(gain.as_ref()).unwrap();
|
||||
// Then connect the gain node to the AudioContext destination (aka your speakers)
|
||||
|
||||
// Then connect the gain node to the AudioContext destination (aka
|
||||
// your speakers).
|
||||
gain_node.connect_with_audio_node(destination_node).unwrap();
|
||||
|
||||
// the FM oscillator is connected to its own gain node, so it can control the amount of modulation
|
||||
fm_osc_node.connect_with_audio_node(fm_gain.as_ref()).unwrap();
|
||||
// The FM oscillator is connected to its own gain node, so it can
|
||||
// control the amount of modulation.
|
||||
fm_osc_node
|
||||
.connect_with_audio_node(fm_gain.as_ref())
|
||||
.unwrap();
|
||||
|
||||
// Connect the FM oscillator to the frequency parameter of the main oscillator, so that the
|
||||
// FM node can modulate its frequency
|
||||
fm_gain_node.connect_with_audio_param(&primary.frequency()).unwrap();
|
||||
// Connect the FM oscillator to the frequency parameter of the main
|
||||
// oscillator, so that the FM node can modulate its frequency.
|
||||
fm_gain_node
|
||||
.connect_with_audio_param(&primary.frequency())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
||||
// start the oscillators!
|
||||
AsRef::<AudioScheduledSourceNode>::as_ref(&primary).start().unwrap();
|
||||
AsRef::<AudioScheduledSourceNode>::as_ref(&fm_osc).start().unwrap();
|
||||
// Start the oscillators!
|
||||
AsRef::<AudioScheduledSourceNode>::as_ref(&primary)
|
||||
.start()
|
||||
.unwrap();
|
||||
AsRef::<AudioScheduledSourceNode>::as_ref(&fm_osc)
|
||||
.start()
|
||||
.unwrap();
|
||||
|
||||
FmOsc {
|
||||
ctx,
|
||||
@ -107,14 +114,17 @@ impl FmOsc {
|
||||
fm_freq_ratio: 0.0,
|
||||
fm_gain_ratio: 0.0,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Sets the gain for this oscillator, between 0.0 and 1.0
|
||||
/// Sets the gain for this oscillator, between 0.0 and 1.0.
|
||||
#[wasm_bindgen]
|
||||
pub fn set_gain(&self, mut gain: f32) {
|
||||
if gain > 1.0 { gain = 1.0; }
|
||||
if gain < 0.0 { gain = 0.0; }
|
||||
if gain > 1.0 {
|
||||
gain = 1.0;
|
||||
}
|
||||
if gain < 0.0 {
|
||||
gain = 0.0;
|
||||
}
|
||||
self.gain.gain().set_value(gain);
|
||||
}
|
||||
|
||||
@ -122,11 +132,10 @@ impl FmOsc {
|
||||
pub fn set_primary_frequency(&self, freq: f32) {
|
||||
self.primary.frequency().set_value(freq);
|
||||
|
||||
// The frequency of the FM oscillator depends on the frequency of the primary oscillator, so
|
||||
// we update the frequency of both in this method
|
||||
// The frequency of the FM oscillator depends on the frequency of the
|
||||
// primary oscillator, so we update the frequency of both in this method.
|
||||
self.fm_osc.frequency().set_value(self.fm_freq_ratio * freq);
|
||||
self.fm_gain.gain().set_value(self.fm_gain_ratio * freq);
|
||||
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@ -135,21 +144,22 @@ impl FmOsc {
|
||||
self.set_primary_frequency(freq);
|
||||
}
|
||||
|
||||
/// This should be between 0 and 1, though higher values are accepted
|
||||
/// This should be between 0 and 1, though higher values are accepted.
|
||||
#[wasm_bindgen]
|
||||
pub fn set_fm_amount(&mut self, amt: f32) {
|
||||
self.fm_gain_ratio = amt;
|
||||
|
||||
self.fm_gain.gain().set_value(self.fm_gain_ratio * self.primary.frequency().value());
|
||||
|
||||
self.fm_gain
|
||||
.gain()
|
||||
.set_value(self.fm_gain_ratio * self.primary.frequency().value());
|
||||
}
|
||||
|
||||
/// This should be between 0 and 1, though higher values are accepted
|
||||
/// This should be between 0 and 1, though higher values are accepted.
|
||||
#[wasm_bindgen]
|
||||
pub fn set_fm_frequency(&mut self, amt: f32) {
|
||||
self.fm_freq_ratio = amt;
|
||||
self.fm_osc.frequency().set_value(self.fm_freq_ratio * self.primary.frequency().value());
|
||||
self.fm_osc
|
||||
.frequency()
|
||||
.set_value(self.fm_freq_ratio * self.primary.frequency().value());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -50,23 +50,35 @@
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
- [Contributing](./contributing.md)
|
||||
- [Testing](./testing.md)
|
||||
- [Internal Design](./design.md)
|
||||
- [JS Objects in Rust](./design/js-objects-in-rust.md)
|
||||
- [Exporting a function to JS](./design/exporting-rust.md)
|
||||
- [Exporting a struct to JS](./design/exporting-rust-struct.md)
|
||||
- [Importing a function from JS](./design/importing-js.md)
|
||||
- [Importing a class from JS](./design/importing-js-struct.md)
|
||||
- [Rust Type conversions](./design/rust-type-conversions.md)
|
||||
- [Types in `wasm-bindgen`](./design/describe.md)
|
||||
- [`js-sys`](./js-sys.md)
|
||||
- [Testing](./js-sys/testing.md)
|
||||
- [Adding More APIs](./js-sys/adding-more-apis.md)
|
||||
- [`web-sys`](./web-sys.md)
|
||||
- [Overview](./web-sys/overview.md)
|
||||
- [Testing](./web-sys/testing.md)
|
||||
- [Logging](./web-sys/logging.md)
|
||||
- [Supporting More Web APIs](./web-sys/supporting-more-web-apis.md)
|
||||
- [Publishing](./publishing.md)
|
||||
- [Team](./team.md)
|
||||
- [`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)
|
||||
- [JS Objects in Rust](./contributing/design/js-objects-in-rust.md)
|
||||
- [Exporting a function to JS](./contributing/design/exporting-rust.md)
|
||||
- [Exporting a struct to JS](./contributing/design/exporting-rust-struct.md)
|
||||
- [Importing a function from JS](./contributing/design/importing-js.md)
|
||||
- [Importing a class from JS](./contributing/design/importing-js-struct.md)
|
||||
- [Rust Type conversions](./contributing/design/rust-type-conversions.md)
|
||||
- [Types in `wasm-bindgen`](./contributing/design/describe.md)
|
||||
- [`js-sys`](./contributing/js-sys/index.md)
|
||||
- [Testing](./contributing/js-sys/testing.md)
|
||||
- [Adding More APIs](./contributing/js-sys/adding-more-apis.md)
|
||||
- [`web-sys`](./contributing/web-sys/index.md)
|
||||
- [Overview](./contributing/web-sys/overview.md)
|
||||
- [Testing](./contributing/web-sys/testing.md)
|
||||
- [Logging](./contributing/web-sys/logging.md)
|
||||
- [Supporting More Web APIs](./contributing/web-sys/supporting-more-web-apis.md)
|
||||
- [Publishing](./contributing/publishing.md)
|
||||
- [Team](./contributing/team.md)
|
||||
|
24
guide/src/contributing/publishing.md
Normal file
24
guide/src/contributing/publishing.md
Normal file
@ -0,0 +1,24 @@
|
||||
# Publishing New `wasm-bindgen` Releases
|
||||
|
||||
1. <input type="checkbox"/> Compile the `publish.rs` script:
|
||||
|
||||
```
|
||||
rustc publish.rs
|
||||
```
|
||||
|
||||
2. <input type="checkbox"/> Bump every crate's minor version:
|
||||
|
||||
```
|
||||
# Make sure you are in the root of the wasm-bindgen repo!
|
||||
./publish bump
|
||||
```
|
||||
|
||||
3. <input type="checkbox"/> Send a pull request for the version bump.
|
||||
|
||||
4. <input type="checkbox"/> After the pull request's CI is green and it has been
|
||||
merged, publish to cargo:
|
||||
|
||||
```
|
||||
# Make sure you are in the root of the wasm-bindgen repo!
|
||||
./publish publish
|
||||
```
|
10
guide/src/contributing/web-sys/index.md
Normal file
10
guide/src/contributing/web-sys/index.md
Normal file
@ -0,0 +1,10 @@
|
||||
# `web-sys`
|
||||
|
||||
The `web-sys` crate provides raw bindings to all of the Web's APIs, and its
|
||||
source lives at `wasm-bindgen/crates/web-sys`.
|
||||
|
||||
The `web-sys` crate is **entirely** mechanically generated inside `build.rs`
|
||||
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!
|
@ -1,40 +0,0 @@
|
||||
# Publishing New `wasm-bindgen` Releases
|
||||
|
||||
* [ ] Make sure that your git working copy is clean.
|
||||
|
||||
* [ ] Make sure that you are on the latest `master`:
|
||||
|
||||
```
|
||||
git pull origin master
|
||||
```
|
||||
|
||||
* [ ] Run `rustc ./publish.rs`
|
||||
|
||||
* [ ] Run `./publish bump` - this will update all version numbers
|
||||
|
||||
* [ ] Write a "0.X.Z" entry in the CHANGELOG.md
|
||||
|
||||
* [ ] Commit the version bump:
|
||||
|
||||
```
|
||||
git commit -m "Bump to version 0.X.Z"
|
||||
```
|
||||
|
||||
* [ ] Send a PR to the `wasm-bindgen` repository, get it merged
|
||||
|
||||
* [ ] Check out the merge commit of `wasm-bindgen`
|
||||
|
||||
* [ ] Comment out the `[patch]` section in the root `Cargo.toml` that only
|
||||
exists to make sure that `console_error_panic_hook` in tests is using
|
||||
*this* `wasm-bindgen` rather than one from crates.io.
|
||||
|
||||
* [ ] Run `rustc ./publish.rs`
|
||||
|
||||
* [ ] Run `./publish publish`
|
||||
|
||||
* [ ] Tag the release and push it:
|
||||
|
||||
```
|
||||
git tag 0.X.Z
|
||||
git push origin --tags
|
||||
```
|
@ -1,103 +0,0 @@
|
||||
# `web-sys`
|
||||
|
||||
The `web-sys` crate provides raw bindings to all of the Web's APIs, and its
|
||||
source lives at `wasm-bindgen/crates/web-sys`.
|
||||
|
||||
The `web-sys` crate is **entirely** mechanically generated inside `build.rs`
|
||||
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
|
15
guide/src/web-sys/cargo-features.md
Normal file
15
guide/src/web-sys/cargo-features.md
Normal 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
|
29
guide/src/web-sys/examples/2d-canvas.md
Normal file
29
guide/src/web-sys/examples/2d-canvas.md
Normal 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}}
|
||||
```
|
BIN
guide/src/web-sys/examples/2d-canvas.png
Normal file
BIN
guide/src/web-sys/examples/2d-canvas.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
23
guide/src/web-sys/examples/fetch.md
Normal file
23
guide/src/web-sys/examples/fetch.md
Normal 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}}
|
||||
```
|
3
guide/src/web-sys/examples/index.md
Normal file
3
guide/src/web-sys/examples/index.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Examples of using `web-sys`
|
||||
|
||||
This subsection contains examples of using the `web-sys` crate.
|
36
guide/src/web-sys/examples/web-audio.md
Normal file
36
guide/src/web-sys/examples/web-audio.md
Normal 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}}
|
||||
```
|
20
guide/src/web-sys/function-overloads.md
Normal file
20
guide/src/web-sys/function-overloads.md
Normal 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
|
23
guide/src/web-sys/index.md
Normal file
23
guide/src/web-sys/index.md
Normal 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
|
22
guide/src/web-sys/type-translations.md
Normal file
22
guide/src/web-sys/type-translations.md
Normal 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/
|
61
guide/src/web-sys/using-web-sys.md
Normal file
61
guide/src/web-sys/using-web-sys.md
Normal 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
|
Loading…
Reference in New Issue
Block a user