コンテンツへスキップ

WebAssemblyがDOM、APIに対応します!

by : 2019/04/05

WebAssemblyはWebアプリケーションを高速に処理できる技術ですが、幾つかの欠点もありました。その一つがDOMを処理できないこと、さらにFetch APIやWebAudioなどのAPIが使えない点です。

しかし先日Announcing the web-sys crate! | Rust and WebAssemblyがアナウンスされ、WebAssemblyでもDOMや各種APIの利用が可能となっています。

実際にはラッピング?

今回発表されたのはweb-sysというクレート(パッケージ)です。すでにWebAssemblyに対応しているWebブラウザであれば利用可能となっていることから、WebAssemblyエンジン自体のバージョンアップは不要なようです。そのため、DOMやAPI操作はメインスレッド側のJavaScriptで行っているかと思われます。ただし、Fetch APIで使ったURLなどはWebブラウザ側のソースにはありませんでした(ネットワークログを見ると、どこにアクセスしたかは分かります)。

Hello World

Hello Worldのアラートを出す場合のコードです。


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));
}

view raw

index.rs

hosted with ❤ by GitHub

DOM操作

DOMに記述する際のコードです。 web_sys クレートを介してWindowやDocumentにアクセスできます。


extern crate wasm_bindgen;
extern crate web_sys;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn run() -> Result<(), JsValue> {
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
let body = document.body().expect("document should have a body");
let val = document.create_element("p")?;
val.set_inner_html("Hello from Rust!");
AsRef::<web_sys::Node>::as_ref(&body).append_child(val.as_ref())?;
Ok(())
}

view raw

index.rs

hosted with ❤ by GitHub

Fetch API

Fetch APIを使って外部リソースを取得するコードです。Promiseを使います。


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 wasm_bindgen_futures::future_to_promise;
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestInit, RequestMode, Response};
#[derive(Debug, Serialize, Deserialize)]
pub struct Branch {
pub name: String,
pub commit: Commit,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Commit {
pub sha: String,
pub commit: CommitDetails,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CommitDetails {
pub author: Signature,
pub committer: Signature,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Signature {
pub name: String,
pub email: String,
}
#[wasm_bindgen]
pub fn run() -> Promise {
let mut opts = RequestInit::new();
opts.method("GET");
opts.mode(RequestMode::Cors);
let request = Request::new_with_str_and_init(
"https://api.github.com/repos/rustwasm/wasm-bindgen/branches/master&quot;,
&opts,
).unwrap();
request
.headers()
.set("Accept", "application/vnd.github.v3+json")
.unwrap();
let window = web_sys::window().unwrap();
let request_promise = window.fetch_with_request(&request);
let future = JsFuture::from(request_promise)
.and_then(|resp_value| {
assert!(resp_value.is_instance_of::<Response>());
let resp: Response = resp_value.dyn_into().unwrap();
resp.json()
}).and_then(|json_value: Promise| {
JsFuture::from(json_value)
}).and_then(|json| {
let branch_info: Branch = json.into_serde().unwrap();
future::ok(JsValue::from_serde(&branch_info).unwrap())
});
future_to_promise(future)
}

view raw

index.rs

hosted with ❤ by GitHub


rustwasm/wasm-bindgen: Facilitating high-level interactions between wasm modules and JavaScriptに多数のサンプルが掲載されていますので、ぜひコードを見てください。動いているコードはExamples – The wasm-bindgen Guideにて確認できます。WebGLやCanvas、WebAudioなどのサンプルが掲載されています。

From → HTML5

コメントは受け付けていません。