Yewを使ってRustでフロントエンド入門してみた

# 概要
最近趣味でRustをやっています。
そのなかで、WASM(WebAssembly)の技術を使ってRustでフロントエンド開発が行えると知ったので少し試しました。
今回はYewというフレームワークのチュートリアルを参考に、環境の立ち上げから簡単なカウンターボタンを表示するところまでやってみます。

# 執筆者について
普段はGoでバックエンド開発をしています。
フロントエンドはたまにAngularをやる程度であまり詳しくありません。
むしろ、昔ながらのPHPのテンプレートエンジンとjQueryをつかった開発の方が長いです。
Rustについても経験浅なので不正確な記述などあればご指摘ください。



# なぜブラウザでRustが動かせるのか
WebAssemblyのおかげ
https://webassembly.org/

当初はWebブラウザ上でJavaScriptで行うには負荷が高い処理を高速で実行させるために開発された技術ですが、最近ではブラウザ上以外でも利用できるようになっています。

RustをWebAssembly形式にコンパイルすることで、ブラウザ上でRustで書いたコードが動かせます。
Rust以外にも、C,　C++やGoもWebAssemblyにコンパイルすることができます。

デザインツールとして有名なFigmaはWebAssemblyを使うことで処理速度を格段に上げることに成功したみたいです。
https://www.figma.com/blog/webassembly-cut-figmas-load-time-by-3x/

# Yew
Rustを単にWebAssemblyにコンパイルするためには特にフレームワークを利用する必要はありません。しかし今回はチュートリアルが充実している、活発に開発されているという理由でYewというフレームワークを試してみます。
Rustでフロントエンド開発を行うフレームワークは各種ありますが、ダウンロード数などはYewが圧倒的です。
※参考
https://github.com/flosse/rust-web-framework-comparison#frontend-frameworks-wasm
この中だったら次はeguiやicedを試してみたいかも

# やってみよう
https://yew.rs/docs/tutorial

## セットアップ

### trunk
まずはtrunkというビルドツールをインストールします。
https://trunkrs.dev/
trunkはRustでWebAssemblyアプリケーションを作るときに利用するビルドツールです。ローカルサーバーもついてて便利、ホットリロードもしてくれます。Yewではこれを使うのが基本のよう


`cargo install trunk`

### WebAssemblyコンパイルのためコンパイルターゲットアーキテクチャ追加
`rustup target add wasm32-unknown-unknown`

これでRustがWeb Assemblyをコンパイルできるようになります。
ちなみにこの変な名前は
https://github.com/rustwasm/wasm-bindgen/issues/979#issuecomment-432632829
>My understanding is that the first unknown is the system that you are compiling on, and the second is the system you are targeting.
>So you an think of unknown-unknown as
>“Compile on almost any machine, run on almost any machine”
>If you look at other targets “unknown” is commonly used so this is in line with the other targets.
>Hope that helps!!

ChatGPTによる日本語翻訳
>私の理解によれば、最初のunknownはコンパイルしているシステムであり、2つ目はターゲットとしているシステムです。
したがって、unknown-unknownは
「ほぼどんなマシン上でもコンパイルし、ほぼどんなマシン上でも実行する」
と考えることができます。
他のターゲットを見ると、「unknown」はよく使われているので、これは他のターゲットと一致しています。
お手伝いできれば幸いです！！


とのことです。

全然関係ないですが、最近読んだ本にソフトウェアを複雑さを表す3つの概念の中の一つにunknown unknownsというものがありました。
https://www.amazon.co.jp/-/en/John-Ousterhout/dp/1732102201
変更などを加えるためにどこに依存関係などがあるか全くわからず手をつける場所が不明になってしまうことらしいです。
よくみるやつですね。

### プロジェクト作成
`cargo new yew-app`

このコマンドを打つことでプロジェクトのディレクトリが作成されます。
cargo.tomlというRustプロジェクトの設定ファイルに以下を記述し、Yewを使えるようにします。
今回はクライアントサイドレンダリングを設定しますが、サーバーサイドレンダリングもできるみたいです。
https://docs.rs/yew/latest/yew/

```
[dependencies]
yew = { version = "0.20", features = ["csr"] }
```

あとはこんなふうに記述して
```rust:src/main.rs
use yew::prelude::*;

#[function_component(App)]
fn app() -> Html {
    html! {
        <h1>{ "Hello World" }</h1>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}
```

プロジェクトルートにhtmlおいて
```html: index.html
<!DOCTYPE html>
<html lang="en">
    <head></head>
    <body></body>
</html>
```

このコマンドでローカルサーバーが立ち上がります。

`trunk serve --open`

スクリーン録画したら遅くなってしまいましたが、実際はホットリロードもっとはやいです。

 ![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316078/618b4f9c-15f7-ff43-e923-7d91e65f6fa1.gif)



## カウンターをつくる
```rust: src/main.rs
use yew::prelude::*;

#[function_component(App)]
fn app() -> Html {
   let counter = use_state(|| 0);
   let onclick = {
       let counter = counter.clone();
       move |_| {
           let value = *counter +1;
           counter.set(value);
       }
   };
   html! {
       <div>
        <button {onclick}>{"+1"}</button>
       <p>{*counter}</p>
       </div>
   }
}

fn main() {
   yew::Renderer::<App>::new().render();
}


```

![output_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316078/fc308055-bd88-4386-d3c1-529f0cecd4c4.gif)


すごーい！


### yew::functional::use_state
Yewでstate管理をするときに使われる関数のようです。
Rustの記法が分かりづらいけど、初期化のときに関数を受け取っています。ここでは初期値を０にしています。

```rust
// || 0 が初期値を入れる関数
let counter = use_state(|| 0);

// これはライブラリ内の定義です
pub fn use_state<T, F>(init_fn: F) -> UseStateHandle<T>
```

### onclick
onclickが押されるとlet onclickが動きます。onclickは関数を返し、move |_| 内部の処理が動きます。これはクロージャーで、moveはcounterの所有権をもった関数を返すための魔法です。

```rust
let onclick = {
   let counter = counter.clone();
   move |_| {
       let value = *counter +1;
       counter.set(value);
   }
};
html! {
   <div>
    <button {onclick}>{"+1"}</button>
   <p>{*counter}</p>
   </div>
}

```

## コンパイラが親切
上記onclickからmoveを消してみました。

```rust
let onclick = {
   let counter = counter.clone();
   |_| {
       let value = *counter +1;
       counter.set(value);
   }
};
html! {
   <div>
    <button {onclick}>{"+1"}</button>
   <p>{*counter}</p>
   </div>
}

```
すると以下のようなコンパイルエラーが出て、moveしないとダメだからつけてみてねと言ってくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316078/2574ae95-5191-b129-ffa1-398d6419208e.png)


# 感想
ブラウザ上でJavaScript以外の言語が動かせるなんてちょっと感動。

ただ今回やったようなことはRustみたいな言語を使う必要はなさそう(むしろVueやReact使う方が簡単)
今後もうちょっと詳しくtodoアプリみたいなチュートリアルもやろうかと思うけど、そのようなものをRustで作る必要があるかも微妙な気がする。
ブラウザ上のWebAssembly自体は、多分こう言うものよりもグラフィックや重い処理をやらせるために使うのが本来の目的なんだろうと思います。

Rustのコンパイラの親切さはYewを使っていても健在でした。
そして今日みたこの本が欲しくなりました。
https://amzn.asia/d/fjTtVmg