2021/05/12に開催した社内向けハンズオンの資料です。
Rust ハンズオン第 5 回WebAssembly 編1
View Slide
目次1. Yew で体験する Rust によるフロントエンド開発2. Web Assembly とは何か?2
本日の免責事項WebAssembly はとくに詳しいわけでも専門ではありません。Rust コミュニティにいると WebAssembly の話を近くで聞くことが多いので、聴いた話を元に情報をまとめ直しています。誤り等ありましたら Slack で教えて下さい。3
Yew で体験する Rust によるフロントエンド開発1. Yew とは2. 裏の仕組み3. 動かす前の事前準備4. カウンタアプリを書いて、動かしてみる4
Yew とはWebAssembly によってマルチスレッドな Web アプリケーションのフロントエンドを作ることができるフレームワーク。Elm や React に使い心地は似ている。5
裏の仕組みRust のビルドターゲットを WebAssembly にすることで、wasm を吐き出せるのでそれを利用している。6
動かす前の準備wasm-pack のインストールminiserve のインストール7
動かす前の準備wasm-packcargo install wasm-pack8
動かす前の準備miniservecargo +nightly install miniserve9
カウンタアプリを書いて、動かしてみるプロジェクトを作成しましょうcargo new --lib coutner-app && cd counter-app10
カウンタアプリを書いて、動かしてみるYew と wasm-bindgen を追加するCargo.toml に追加してください。[dependencies]yew = "0.17"wasm-bindgen = "0.2"11
カウンタアプリを書いて、動かしてみるcrate-type を変えるCargo.toml に追加してください。[lib]crate-type = ["cdylib", "rlib"]12
カウンタアプリを書いて、動かしてみるuse wasm_bindgen::prelude::*;use yew::prelude::*;struct Model {link: ComponentLink,value: i64,}enum Msg {AddOne,}impl Component for Model {type Message = Msg;type Properties = ();fn create(_: Self::Properties, link: ComponentLink) -> Self {Self {link,value: 0,}}fn update(&mut self, msg: Self::Message) -> ShouldRender {match msg {Msg::AddOne => self.value += 1}true}fn change(&mut self, _props: Self::Properties) -> ShouldRender {false}fn view(&self) -> Html {html! {{ "+1" }{ self.value }}}}#[wasm_bindgen(start)]pub fn run_app() {App::::new().mount_to_body();} 13
カウンタアプリを書いて、動かしてみるstaticというディレクトリを作る。下記を含む index.htmlを書く。Yew Sample App<br/><br/>import init from "./wasm.js";<br/><br/>init();<br/><br/>14
カウンタアプリを書いて、動かしてみる起動してみましょうwasm-pack build --target web --out-name wasm --out-dir ./staticminiserve ./static --index index.html15
カウンタアプリを書いて、動かしてみるComponentトレイトが実質の処理の中心になっている。16
カウンタアプリを書いて、動かしてみるComponent トレイト重要な内容を取り出して説明します。pub trait Component: Sized + 'static {type Message: 'static;type Properties: Properties;fn create(props: Self::Properties, link: ComponentLink) -> Self;fn update(&mut self, msg: Self::Message) -> ShouldRender;fn change(&mut self, _props: Self::Properties) -> ShouldRender;fn view(&self) -> Html;}17
カウンタアプリを書いて、動かしてみるMessageコンポーネントによって処理され、何らかの副作用を引き起こすことができるさまざまなメッセージを表す。API リクエストをトリガーしたりなどを行う。今回は「 AddOne」という命令を enum の variant として定義しておき、カウンタを増加させる実装をしている。18
カウンタアプリを書いて、動かしてみるPropertiesReact などの Properties と同じ。親からコンポーネントに渡される情報を表す。今回は実装していないが、 Propertiesトレイトというものがあり、使用する際はそれを実装している必要がある。19
カウンタアプリを書いて、動かしてみるcreateライフサイクルフックの一つ。コンポーネントの初期化などを行う。Propertiesの受け取りは React と同じように。ComponentLinkは、コンポーネントに登録可能なコールバックを管理したり、コンポーネントの更新の範囲を制御したりする際に使用できる機能。fn create(_: Self::Properties, link: ComponentLink) -> Self {Self {link,value: 0,}}20
カウンタアプリを書いて、動かしてみるupdateメッセージを受け取り、副作用のあるコンポーネント内の状態更新を行う。ShouldRenderはレンダリングし直すかどうかを制御できる型。fn update(&mut self, msg: Self::Message) -> ShouldRender {match msg {Msg::AddOne => self.value += 1}true}21
カウンタアプリを書いて、動かしてみるchange親コンポーネントから再レンダリングを要求された場合の動作を制御できる。新しくプロパティの内容を受け取り、その内容を元に再レンダリングさせるといった手が取れる。fn change(&mut self, _props: Self::Properties) -> ShouldRender {false}22
カウンタアプリを書いて、動かしてみるviewHTML を書いて UI を宣言できる。html!マクロにより素の HTML が書ける ← 黒魔術すぎてすごいfn view(&self) -> Html {html! {{ "+1" }{ self.value }}}23
増やしたカウンタを減らす実装を追加してみましょうMsgに SubOne命令を追加する。update関数のパターンマッチングで、 SubOne命令を受け取るパターンマッチの腕を追加し、カウントを 1 減らす処理を書く。viewに -1と表記されたボタンを追加する。24
使ってみての疑問CSS とかどうするの?現時点では外部 css に定義するしかなさそう?ごめんなさい調べ中です。個人的には React にそろえてくれると嬉しい。25
WebAssembly とは何か?26
WebAssembly とは何かブラウザ上で実行できるバイナリ形式のこと。ユーザーは作り方を知らなくてよいくらい隠蔽されている。WebAssembly は JavaScript の置き換えを意図してはいない。27
https://blog.logrocket.com/webassembly-how-and-why-559b7f96cd71/ 28
wasm と watWebAssembly はバイナリフォーマットなので、(なれていない限り)読むことはできない。WebAssembly Text Format に直すと読める。wasm2wat というツールを使うか、ブラウザで: https://webassembly.github.io/wabt/demo/wasm2wat/wat は S 式で表現される形式。先ほど作った Yew の wasm を wat にして見てみましょう。29
ブラウザで動くとはどういうことか?https://forge.autodesk.com/ja/node/143430
WebAssembly の良さJavaScript と比較すると処理速度が安定的で実行速度を制御しやすいJavaScript よりも速くなるケースがある安全であるWebAssembly そのものがひとつの規格になっていて、ポータビリティがある31
JavaScript と比較すると処理速度が安定的で実行速度を制御しやすい実行時の最適化をあまり伴わない。コンパイルタイムで最適化が走る。ブラウザによっては JIT を用いるものもあるらしい。ただしいずれにせよ最適化は事前に行われる。気まぐれな速度向上や低下が起きにくくなる。32
JavaScript よりも速くなるケースがあるコンパイルタイムでバイナリを生成し、最適化まで行った状態にするため。JavaScript と比べると機械語に近くなる。コンパイルそのものはストリーミングで行う。コードが届いたタイミングで逐一コンパイルが行われ、バイナリに直される。それを可能にするようなバイナリフォーマットを持っている。興味のある方向け: https://livebook.manning.com/book/webassembly-in-action/chapter-2/1533
https://medium.com/@tydxapp/this-article-is-the-third-part-of-a-series-of-posts-about-our-journey-on-webassembly-8d1fafdc4b9834
安全であるWebAssembly はサンドボックス化された実行環境上で動作するように設計されている。WebAssembly はホスト側のメモリには直接アクセスしないように設計されている。代わりに線形メモリと呼ばれるバイト列を使用してメモリを管理する。35
WebAssembly そのものがひとつの規格になっていて、ポータビリティがあるこれは後ほど話をするが、WebAssembly ランタイムというものを作って、さまざまな環境で使用できる実行環境として使っていく策が模索されている。36
WebAssembly はどこで使われているの?Google Meet のぼかし機能: https://zenn.dev/kounoike/articles/google-meet-bg-featuresGoogle Earth: https://medium.com/google-earth/google-earth-comes-to-more-browsers-thanks-to-webassembly-1877d95810d6eBay のバーコード読み取り: https://medium.com/ebaytech/webassembly-at-ebay-a-real-world-use-case-ef888f38b537弊社でも利用した記事を見つけた。mp3 エンコーダを WebAssembly 化して使用するという手: https://developers.cyberagent.co.jp/blog/archives/20506/vim.wasm: https://github.com/rhysd/vim.wasm画像処理関係、音声関係(Google Meet では雑音抑制にも使われているらしい)での利用事例が多い。あるいは、ブラウザゲームでの利用が期待されると言われている。37
ブラウザ外の WebAssembly38
ブラウザの外で WebAssembly を使うってどういうこと?ブラウザの中で、ファイルアクセスやネットワークが扱えるのはなんとなくわかる。でも、ブラウザの外でそれを可能にするには一体どうやるの…?39
WASI: WebAssembly System InterfaceWebAssembly でファイルアクセスやネットワークを扱えるようにするもの。ただ、OS に直接アクセスさせるわけではなく、間に wasm が入る。ので、安全。POSIX みたいなもの。まだ開発途上。40
WebAssembly ランタイムという存在WASI に対応した WebAssembly ランタイムが作られている。ランタイムをインストールした環境であればどこでも実行可能ということ。代表的なものは下記。Wasmer: サポート言語やコンパイラバックエンドが広い。Wasmtime: 小さいのがウリらしい。Lucet: Fastly 社が作っている。WebAssembly を出力可能な言語なら、この上で普通に動かせる。Go でも C でも Rustでも Swift でも…!41
Web の外の WebAssembly の具体的な利用例Proxy-Wasm: プロキシサーバと拡張機能との間の ABI を定義するもの。たとえば Envoyに使用されているものが最近話題。Krustlet: Kubernetes 上で wasm コンテナを実現するプロジェクトKernel-wasm: Linux カーネル上でコンテキストスイッチなしで wasm バイナリを動かせる。42
まとめWebAssembly はブラウザ上で動かせるバイナリ形式のフォーマットだった。が、近年ではそのポータビリティによって、ブラウザの外で動かすランタイムとしての使い方が模索されている。発展途上の技術なので、これからの動向は引き続き注視する必要がある。43