$30 off During Our Annual Pro Sale. View Details »

Rustハンズオン第5回 WebAssembly編

Yuki Toyoda
May 15, 2021
2.3k

Rustハンズオン第5回 WebAssembly編

2021/05/12に開催した社内向けハンズオンの資料です。

Yuki Toyoda

May 15, 2021
Tweet

Transcript

  1. Rust ハンズオン第 5 回
    WebAssembly 編
    1

    View Slide

  2. 目次
    1. Yew で体験する Rust によるフロントエンド開発
    2. Web Assembly とは何か?
    2

    View Slide

  3. 本日の免責事項
    WebAssembly はとくに詳しいわけでも専門ではありません。
    Rust コミュニティにいると WebAssembly の話を近くで聞くことが多いので、聴いた話
    を元に情報をまとめ直しています。
    誤り等ありましたら Slack で教えて下さい。
    3

    View Slide

  4. Yew で体験する Rust によるフロントエンド開発
    1. Yew とは
    2. 裏の仕組み
    3. 動かす前の事前準備
    4. カウンタアプリを書いて、動かしてみる
    4

    View Slide

  5. Yew とは
    WebAssembly によってマルチスレッドな Web アプリケーションのフロントエンドを作
    ることができるフレームワーク。
    Elm や React に使い心地は似ている。
    5

    View Slide

  6. 裏の仕組み
    Rust のビルドターゲットを WebAssembly にすることで、wasm を吐き出せるのでそれ
    を利用している。
    6

    View Slide

  7. 動かす前の準備
    wasm-pack のインストール
    miniserve のインストール
    7

    View Slide

  8. 動かす前の準備
    wasm-pack
    cargo install wasm-pack

    8

    View Slide

  9. 動かす前の準備
    miniserve
    cargo +nightly install miniserve

    9

    View Slide

  10. カウンタアプリを書いて、動かしてみる
    プロジェクトを作成しましょう
    cargo new --lib coutner-app && cd counter-app

    10

    View Slide

  11. カウンタアプリを書いて、動かしてみる
    Yew と wasm-bindgen を追加する
    Cargo.toml に追加してください。
    [dependencies]

    yew = "0.17"

    wasm-bindgen = "0.2"

    11

    View Slide

  12. カウンタアプリを書いて、動かしてみる
    crate-type を変える
    Cargo.toml に追加してください。
    [lib]

    crate-type = ["cdylib", "rlib"]

    12

    View Slide

  13. カウンタアプリを書いて、動かしてみる
    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

    View Slide

  14. カウンタアプリを書いて、動かしてみる
    static
    というディレクトリを作る。
    下記を含む index.html
    を書く。








    Yew Sample App

    <br/><br/>import init from "./wasm.js";<br/><br/>init();<br/><br/>







    14

    View Slide

  15. カウンタアプリを書いて、動かしてみる
    起動してみましょう
    wasm-pack build --target web --out-name wasm --out-dir ./static

    miniserve ./static --index index.html

    15

    View Slide

  16. カウンタアプリを書いて、動かしてみる
    Component
    トレイトが実質の処理の中心になっている。
    16

    View Slide

  17. カウンタアプリを書いて、動かしてみる
    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

    View Slide

  18. カウンタアプリを書いて、動かしてみる
    Message
    コンポーネントによって処理され、何らかの副作用を引き起こすことができるさまざま
    なメッセージを表す。
    API リクエストをトリガーしたりなどを行う。
    今回は「 AddOne
    」という命令を enum の variant として定義しておき、カウンタを増
    加させる実装をしている。
    18

    View Slide

  19. カウンタアプリを書いて、動かしてみる
    Properties
    React などの Properties と同じ。
    親からコンポーネントに渡される情報を表す。
    今回は実装していないが、 Properties
    トレイトというものがあり、使用する際はそれ
    を実装している必要がある。
    19

    View Slide

  20. カウンタアプリを書いて、動かしてみる
    create
    ライフサイクルフックの一つ。
    コンポーネントの初期化などを行う。
    Properties
    の受け取りは React と同じように。
    ComponentLink
    は、コンポーネントに登録可能なコールバックを管理したり、コンポ
    ーネントの更新の範囲を制御したりする際に使用できる機能。
    fn create(_: Self::Properties, link: ComponentLink) -> Self {

    Self {

    link,

    value: 0,

    }

    }

    20

    View Slide

  21. カウンタアプリを書いて、動かしてみる
    update
    メッセージを受け取り、副作用のあるコンポーネント内の状態更新を行う。
    ShouldRender
    はレンダリングし直すかどうかを制御できる型。
    fn update(&mut self, msg: Self::Message) -> ShouldRender {

    match msg {

    Msg::AddOne => self.value += 1

    }

    true

    }

    21

    View Slide

  22. カウンタアプリを書いて、動かしてみる
    change
    親コンポーネントから再レンダリングを要求された場合の動作を制御できる。
    新しくプロパティの内容を受け取り、その内容を元に再レンダリングさせるといった手
    が取れる。
    fn change(&mut self, _props: Self::Properties) -> ShouldRender {

    false

    }

    22

    View Slide

  23. カウンタアプリを書いて、動かしてみる
    view
    HTML を書いて UI を宣言できる。
    html!
    マクロにより素の HTML が書ける ← 黒魔術すぎてすごい
    fn view(&self) -> Html {

    html! {



    { "+1" }

    { self.value }



    }

    }

    23

    View Slide

  24. 増やしたカウンタを減らす実装を追加してみましょう
    Msg
    に SubOne
    命令を追加する。
    update
    関数のパターンマッチングで、 SubOne
    命令を受け取るパターンマッチの腕
    を追加し、カウントを 1 減らす処理を書く。
    view
    に -1
    と表記されたボタンを追加する。
    24

    View Slide

  25. 使ってみての疑問
    CSS とかどうするの?
    現時点では外部 css に定義するしかなさそう?
    ごめんなさい調べ中です。
    個人的には React にそろえてくれると嬉しい。
    25

    View Slide

  26. WebAssembly とは何か?
    26

    View Slide

  27. WebAssembly とは何か
    ブラウザ上で実行できるバイナリ形式のこと。
    ユーザーは作り方を知らなくてよいくらい隠蔽されている。
    WebAssembly は JavaScript の置き換えを意図してはいない。
    27

    View Slide

  28. https://blog.logrocket.com/webassembly-how-and-why-559b7f96cd71/ 28

    View Slide

  29. wasm と wat
    WebAssembly はバイナリフォーマットなので、(なれていない限り)読むことはでき
    ない。
    WebAssembly Text Format に直すと読める。
    wasm2wat というツールを使うか、
    ブラウザで: https://webassembly.github.io/wabt/demo/wasm2wat/
    wat は S 式で表現される形式。
    先ほど作った Yew の wasm を wat にして見てみましょう。
    29

    View Slide

  30. ブラウザで動くとはどういうことか?
    https://forge.autodesk.com/ja/node/1434
    30

    View Slide

  31. WebAssembly の良さ
    JavaScript と比較すると処理速度が安定的で実行速度を制御しやすい
    JavaScript よりも速くなるケースがある
    安全である
    WebAssembly そのものがひとつの規格になっていて、ポータビリティがある
    31

    View Slide

  32. JavaScript と比較すると処理速度が安定的で実行速度を制御しやすい
    実行時の最適化をあまり伴わない。
    コンパイルタイムで最適化が走る。
    ブラウザによっては JIT を用いるものもあるらしい。
    ただしいずれにせよ最適化は事前に行われる。
    気まぐれな速度向上や低下が起きにくくなる。
    32

    View Slide

  33. JavaScript よりも速くなるケースがある
    コンパイルタイムでバイナリを生成し、最適化まで行った状態にするため。
    JavaScript と比べると機械語に近くなる。
    コンパイルそのものはストリーミングで行う。コードが届いたタイミングで逐一コンパ
    イルが行われ、バイナリに直される。
    それを可能にするようなバイナリフォーマットを持っている。
    興味のある方向け: https://livebook.manning.com/book/webassembly-in-
    action/chapter-2/15
    33

    View Slide

  34. https://medium.com/@tydxapp/this-article-is-the-third-part-of-a-series-of-posts-about-
    our-journey-on-webassembly-8d1fafdc4b98
    34

    View Slide

  35. 安全である
    WebAssembly はサンドボックス化された実行環境上で動作するように設計されてい
    る。
    WebAssembly はホスト側のメモリには直接アクセスしないように設計されている。代
    わりに線形メモリと呼ばれるバイト列を使用してメモリを管理する。
    35

    View Slide

  36. WebAssembly そのものがひとつの規格になっていて、ポータビリティがある
    これは後ほど話をするが、WebAssembly ランタイムというものを作って、さまざまな
    環境で使用できる実行環境として使っていく策が模索されている。
    36

    View Slide

  37. WebAssembly はどこで使われているの?
    Google Meet のぼかし機能: https://zenn.dev/kounoike/articles/google-meet-bg-
    features
    Google Earth: https://medium.com/google-earth/google-earth-comes-to-more-
    browsers-thanks-to-webassembly-1877d95810d6
    eBay のバーコード読み取り: 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

    View Slide

  38. ブラウザ外の WebAssembly
    38

    View Slide

  39. ブラウザの外で WebAssembly を使うってどういうこと?
    ブラウザの中で、ファイルアクセスやネットワークが扱えるのはなんとなくわかる。
    でも、ブラウザの外でそれを可能にするには一体どうやるの…?
    39

    View Slide

  40. WASI: WebAssembly System Interface
    WebAssembly でファイルアクセスやネットワークを扱えるようにするもの。
    ただ、OS に直接アクセスさせるわけではなく、間に wasm が入る。ので、安全。
    POSIX みたいなもの。
    まだ開発途上。
    40

    View Slide

  41. WebAssembly ランタイムという存在
    WASI に対応した WebAssembly ランタイムが作られている。
    ランタイムをインストールした環境であればどこでも実行可能ということ。
    代表的なものは下記。
    Wasmer: サポート言語やコンパイラバックエンドが広い。
    Wasmtime: 小さいのがウリらしい。
    Lucet: Fastly 社が作っている。
    WebAssembly を出力可能な言語なら、この上で普通に動かせる。Go でも C でも Rust
    でも Swift でも…!
    41

    View Slide

  42. Web の外の WebAssembly の具体的な利用例
    Proxy-Wasm: プロキシサーバと拡張機能との間の ABI を定義するもの。たとえば Envoy
    に使用されているものが最近話題。
    Krustlet: Kubernetes 上で wasm コンテナを実現するプロジェクト
    Kernel-wasm: Linux カーネル上でコンテキストスイッチなしで wasm バイナリを動かせ
    る。
    42

    View Slide

  43. まとめ
    WebAssembly はブラウザ上で動かせるバイナリ形式のフォーマットだった。
    が、近年ではそのポータビリティによって、ブラウザの外で動かすランタイムとしての
    使い方が模索されている。
    発展途上の技術なので、これからの動向は引き続き注視する必要がある。
    43

    View Slide