search
LoginSignup
45
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Organization

Rust / yew で 仮想DOMなウェブアプリケーションを作ってみた

前提として、自分の Rustの知識は 1年に1回ぐらい思い立った時にちょろっとやるぐらいで、基礎文法をググりながら、複雑なライフタイムとか書こうとすると手が止まる程度の知識。勘で書いてる。

前提

cargo build --target wasm-unknown-unknown ができるようになるまでは省略。

調べた感じ、Rust の wasm ビルドでウェブの何かしらをやろうとすると、次のような選択肢がある。

  • プレーンな wasm。基本的に数値(float)だけしか扱えない。ポインタの開始位置とサイズを返し、wasm メモリ空間のArrayBufferを自前でデコードする
  • https://github.com/rustwasm/wasm-bindgen : ↑で生成された wasm の読み込みラッパーやTSの型定義、Rust 側からJSのメモリ空間を参照する諸々をやってくれるツール。
  • js-sys: ↑の中で、より高水準なラッパー。開発中らしくドキュメントが少ない。追記: ECMA262 の API の Date や Console などを実装しようとしていた
  • web-sys: もっと抽象度が高そうな何か?開発中らしくドキュメントがない。ちゃんと調べてない。追記: WebIDL から DOM API を生成しようとしていた。
  • https://github.com/koute/stdweb wasm-bindgen とは別系列の高水準なJSラッパー。

生で使う以外は、主に stdweb と wasm-bindgen の2系列ある。 両方使ってみた感想だと、 stdweb はすべてを rust で管理しようとする感じで、 wasm-bindgen は webpack などの js エコシステムで連携しながら使うといった感じ。

Yew

stdweb に依存。Redux のパクリ元の Elm のアーキテクチャと仮想DOMを実装している。自分がReactに慣れてるので、これで遊んでみることにする。

カウンター作ってみた

こんなやつ

デプロイしておいた。IE以外は動く https://frosty-clarke-3d3c34.netlify.com
stdweb が emscripten 通せば asm.js ビルドをサポートしているので、頑張れば動きそう。今回は頑張らない。

コードはここ https://github.com/mizchi-sandbox/hello_cargo_web_yew

コード抜粋

#[macro_use]
extern crate yew;
use std::result::Result::{Err, Ok};
use yew::prelude::{App, Component, ComponentLink, Html, Renderable, ShouldRender};
use yew::services::ConsoleService;

struct Model {
  console: ConsoleService,
  value: i64,
  adding_value_text: String,
}

enum Msg {
  Increment,
  AddByAddingValue,
  SetAddingValue(String),
}

impl Component for Model {
  type Message = Msg;
  type Properties = ();

  fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
    Model {
      console: ConsoleService::new(),
      value: 0,
      adding_value_text: "".to_string(),
    }
  }

  fn update(&mut self, msg: Self::Message) -> ShouldRender {
    match msg {
      Msg::Increment => {
        self.value = self.value + 1;
        true
      }
      Msg::AddByAddingValue => {
        match &self.adding_value_text.parse::<i64>() {
          Ok(v) => {
            self.value = self.value + v;
            self.adding_value_text = "".to_string();
          }
          Err(_) => {
            self.console.log("Parse error");
          }
        };
        true
      }
      Msg::SetAddingValue(value) => {
        self.adding_value_text = value;
        true
      }
    }
  }
}

impl Renderable<Model> for Model {
  fn view(&self) -> Html<Self> {
    html! {
        <div>
          <div>
            <button onclick=|_| Msg::Increment,>{ "Increment" }</button>
          </div>

          <div>
            <button onclick=|_| Msg::AddByAddingValue,>{ "Add" }</button>
            <input
              oninput=|e| Msg::SetAddingValue(e.value),
              value=&self.adding_value_text,
            />
          </div>

          <p>{ self.value }</p>
        </div>
    }
  }
}

fn main() {
  yew::initialize();
  App::<Model>::new().mount_to_body();
  yew::run_loop();
}

ややこしかったのは、文字列をパースするときのパターンマッチで、ちょっと調べた。あと yew 0.5.0 が cargo にリリースされてなかったので、 Cargo.toml で GitHub を直接参照している。ドキュメント や examples が 0.5.0 のものしかない。

性能評価

こういうライブラリ、やたらライブラリサイズが大きかったりしないか?と調べてみた。

ビルドサイズ。

$ ls -l target/deploy
total 368
drwxr-xr-x  5 mz  staff   160B  8 18 22:45 .
drwxr-xr-x  7 mz  staff   224B  8 18 21:54 ..
-rw-r--r--  1 mz  staff    27K  8 18 22:45 counter.js
-rw-r--r--  1 mz  staff   151K  8 18 22:45 counter.wasm
-rw-r--r--  1 mz  staff   815B  8 18 22:45 index.html

180k。react + react-dom が 130k なのを考えると、問題なし。

実際の評価時間。

特に問題なさそう。

感想

JSXのマクロがあって、React/Elm知ってると、 yew の examples を参照すると素直に書ける感じ。特に戸惑うことはなかった。正直 Rust の数値変換とかパターンマッチの文法思い出すほうが時間かかった。

Rustエコシステム全般の話だが、 nightly じゃないと何かと動かない。だいたいマクロ拡張は nightly 使わないと駄目。wasm 周り特有の事情かどうかは推し量れてないが、 stable に全く人権がないのに、nightly を使ったら自己責任みたいな雰囲気がちょっとつらかった。stable と nightly の間のバージョンがほしい。

実際にウェブアプリ書く場合、 wasm-bindgen + js-sys と stdweb の目指してる世界が似てて、どっちが主流になるかわからない不安がある。できれば相互に乗り入れられるようになってほしい。

しかし思ったよりも現実的にアプリが書けそう、といった感触で、JS資産を参照しなくていい、グラフ可視化ツールみたいな複雑なアプリケーションなら思ってたより選択肢になりそう、といった感想。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
45
Help us understand the problem. What are the problem?