🌟

RustのフレームワークYewを使ってみる①

2023/09/12に公開

はじめに

WebアプリケーションをRustで作ってみたときのメモです。
Podman Desktopを使って、コンテナ環境で開発していきます。
まずは、公式のテンプレートを実行してみるところまでやってみる。
公式のテンプレートのyewバージョンは、0.20です。

ディレクトリ構成

まずが、↓のような感じディレクトを作成。

Yewproject/  
├── yewapp/
│   └── Dockerfile
└── docker-compose.yml

公式が準備した最小構成のテンプレートをダウンロードして、yewtestディレクトリに必要最小限のものを保存。
https://github.com/yewstack/yew-trunk-minimal-template

Yewproject/  
├── yewapp/
│   ├── src
│   │   ├── app.rs
│   │   └── main.rs
│   ├── Cargo.lock
│   ├── Cargo.toml
│   ├── Dockerfile
│   ├── index.html
│   └── index.scss
└── docker-compose.yml

docker-compose.ymlとDockerfikeの作成

podmanはdockerと同様のファイルでコンテナを作成することができて、非常にありがたい。
Rustのコンテナイメージも公式のものをそのまま使用できる。

docker-compose.yml
version: "3"
services:
  yapp:
    build: ./yewapp
    ports:
      - 8081:8081
    volumes:
      - ./yewapp:/app/src/myapp
    tty: true   #コンテナ常時起動

今回は、軽量なslim-bookwormディストリビューションを使用する。
※Alpine版も軽量だが、インストールが簡単にはいかないことがあった

Dockerfile
FROM rust:slim-bookworm
# ワーキングディレクトリを作成
WORKDIR /app/src/myapp

# trunkのインストール(Yewの推奨管理ツール)
RUN cargo install --locked trunk
#wasmのターゲットを追加
RUN rustup target add wasm32-unknown-unknown

# 単体でhtmlを表示するためにインストール
RUN cargo install miniserve

trunkのインストールとWASMターゲットの追加は公式を参照。
https://yew.rs/ja/docs/getting-started/introduction

実行してみる

Yewappディレクトリでpodman-composeを使用して、Dockerイメージの構築とコンテナの構築・実行。

podman-compose build
podman-compose up -d

実行されているコンテナ内でtrunkコマンドを使用して、ビルド・ウェブサーバ起動。
コンテナ環境で実行するため、--address 0.0.0.0オプションを追加し、docker-compose.ymlで指定したポート8081を指定。

podman-compose exec yewapp trunk serve --address 0.0.0.0 --port 8081

ターミナルに表示されたアドレスにアクセスし、きちんと表示されることを確認する。

正常に実行されると、distディレクトリとtargetディレクトリが自動で生成され、htmlファイルなどが自動で生成される。

Yewproject/  
├── yewapp/
│   ├── dist
│   │   ├── index-****************
│   │   ├── index.html
│   │   ├── trunk-template-****************.wasm
│   │   └── trunk-template-****************.js
│   ├── src
│   │   ├── app.rs
│   │   └── main.rs
│   ├── target
│   │   ├── debug
│   │   ├── wasm-bindgen
│   │   ├── wasm32-unknown-unknown
│   │   ├── .rustc_info.json
│   │   └── CACHEDIR.TAG
│   ├── Cargo.lock
│   ├── Cargo.toml
│   ├── Dockerfile
│   ├── index.html
│   └── index.scss
└── docker-compose.yml

確認できたら、Ctrl+cでサーバを停止しておきます。

trunkコマンド

今回実行したtrunk serveはtrunk buildとtrunk watchの機能を含んだコマンドです。
https://trunkrs.dev/commands/

  • trunk build:Dockerfileで指定したwasm32 命令セットをターゲットとしたCargoビルドを実行し、ビルドされたWASM上でwasm-bindgenを実行し、ターゲットの index.htmlで定義されたアセット用のアセットビルドパイプラインを生成します。
  • trunk watch:trunk buildと同じことを行うが、ファイルシステムの変更も監視し、変更が検出されたときに新しいビルドを開始する
  • trunk serve:trunk watchと同じことを行うが、ウェブサーバも起動する

Rustプログラムを確認してみる

テンプレートのRustプログラムをそれぞれ確認してみます。

main.rs
mod app;

use app::App;

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

main.rsでは、appモジュールを読み込み、appモジュール内のApp関数を表示するようになっているみたいです。

app.rs
use yew::prelude::*;

#[function_component(App)]
pub fn app() -> Html {
    html! {
        <main>
            <img class="logo" src="https://yew.rs/img/logo.png" alt="Yew logo" />
            <h1>{ "Hello World!" }</h1>
            <span class="subtitle">{ "from Yew with " }<i class="heart" /></span>
        </main>
    }
}

app.rsでは、表示させる内容をHtml構造体で返すapp関数で記述しているようです。
Yewの公式によると、関数コンポーネントを作成するには、関数に#[function_composent]属性(アトリビュート)を追加します。慣例として、関数は他のコンポーネントと同様にパスカルケースで命名されます。
ダウンロードしてきたプログラムでは、function_componentの引数でコンポーネントの名前を定義しているが、公式のCreating function componentsによると関数名をそのままコンポーネントの名前にできるようなので、書き換えてみる。
https://yew.rs/ja/docs/concepts/function-components#creating-function-components

app.rs
use yew::prelude::*;

#[function_component]    // (App)を削除
pub fn App() -> Html {   // appをAppに書き換え
    html! {
        <main>
            <img class="logo" src="https://yew.rs/img/logo.png" alt="Yew logo" />
            <h1>{ "Hello World!" }</h1>
            <span class="subtitle">{ "from Yew with " }<i class="heart" /></span>
        </main>
    }
}

少しだけシンプルになりました。
再度、trunk serveして、プログラムがきちんとビルドされることを確認します。

htmlファイルを確認してみる

テンプレートのRustプログラムをそれぞれ確認してみます。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Trunk Template</title>
    <link data-trunk rel="sass" href="index.scss" />
  </head>
</html>

文字コードとタイトル、cssファイルが定義されているだけです。
scssファイルは、trunkを介して読み込み・ビルドされるため、data-trunkを書く必要があるようです。

次回

コンソールなどの機能を使えるようにしたい。

Discussion