30
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2023-06-22

概要

最近趣味で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を試してみたいかも

やってみよう

セットアップ

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"] }

あとはこんなふうに記述して

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おいて

index.html
<!DOCTYPE html>
<html lang="en">
    <head></head>
    <body></body>
</html>

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

trunk serve --open

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

output.gif

カウンターをつくる

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

すごーい!

yew::functional::use_state

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

// || 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の所有権をもった関数を返すための魔法です。

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を消してみました。

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

感想

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

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

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

30
17
0

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
  3. You can use dark theme
What you can do with signing up
30
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?