この記事の概要
Rust、流行ってますよね。
自分は「良い感じらしい」以上の情報を持っていなかったのですが、手を出してみたくなりました。
しかし、体系的に覚えようと思ってチュートリアルを眺めてもかなり難しく見えます。
というわけで「WebアプリケーションをRustで作れる」というYewで、まずは雰囲気を知ろうと思い挑戦しました。
Yewへのリンクなど
Yewの公式ドキュメントはこちらです。
基本的にはチュートリアルに倣って進めますが、気になった箇所を多少調べながら記事を書きました
ヘッダーに言語変更のUIがあり日本語
も選べますが、ほとんど翻訳されていません。
素直に英語で進めた方が良い気がします。
環境構築
Getting Started
ではRustのインストール方法までは記載されていないため、自分でセットアップしましょう。
最近弊社の同僚が環境準備のための記事を書いていたので紹介します。
アプリケーションの構築やバンドル、Webへの配信のためにTrunkを追加します。
cargo install --locked trunk
WebAssemblyのブラウザ用コンパイルターゲットとしてwasm32-unknown-unknown
を追加します。
rustup target add wasm32-unknown-unknown
プロジェクトのセットアップをします。
cargo new
で作成するか、ディレクトリを作った後にcargo init
します。
cargo new yew-app
cd yew-app
mkdir yew-app
cd yew-app
cargo init
パターン1の方が少ないコマンドで済みますが、自分はうっかり先にディレクトリを切っていたのでパターン2で作りました。
どちらも中身は変わりません。
.
├── .gitignore
├── Cargo.toml
└── src
└── main.rs
コンソールへのHello World
ここで一度Cargo run
してみます。
cargo run
するとコンソールにHello, world!
と表示され、target
ディレクトリとCargo.lock
が生成されました。
.
├── Cargo.lock
├── Cargo.toml
├── src
│ └── main.rs
└── target
├── 以下略
ブラウザへのHello World
ここまでは単にCargoのコマンドで、ようやくYewを使っていきます。
まずはCargo.toml
を編集します。
[package]
name = "my-first-yew"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+ yew = { version = "0.20", features = ["csr"] }
次に、src/main.rc
を触ってみます。
+ use yew::prelude::*;
+
+ #[function_component(App)]
+ fn app() -> Html {
+ html! {
+ <h1>{ "Hello World" }</h1>
+ }
+ }
+
fn main() {
- println!("Hello, world!");
+ yew::Renderer::<App>::new().render();
}
新規にindex.html
を作り、コードを書きます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My first Yew</title>
</head>
<body></body>
</html>
ローカルサーバーを立ち上げます。
trunk serve --open
非常にシンプルなページが開きました。
興味本位の実験
「単なる文字列しか渡していないし、{}
無しでもいけるんじゃないの?」と思って外してみました。
use yew::prelude::*;
#[function_component(App)]
fn app() -> Html {
html! {
- <h1>{ "Hello World" }</h1>
+ <h1>"Hello World"</h1>
}
}
fn main() {
yew::Renderer::<App>::new().render();
}
ダメみたいですね。
error: expected a valid html element
--> src/main.rs:7:17
|
7 | <h1>"Hello World"</h1>
| ^^^^^^^^^^^^^
error: could not compile `my-first-yew` due to previous error
2022-12-18T13:20:59.548671Z ERROR ❌ error
error from HTML pipeline
Caused by:
0: error from asset pipeline
1: error during cargo build execution
2: cargo call returned a bad status
ちょっとしたロジックの追加
今は静的なテキストだけなので、簡単なロジックを追加します。
use yew::prelude::*;
#[function_component]
fn App() -> Html {
+ let counter = use_state(|| 0);
+ let onclick = {
+ let counter = counter.clone();
+ move |_| {
+ let value = *counter + 1;
+ counter.set(value);
+ }
+ };
+
html! {
- <h1>{ "Hello World" }</h1>
+ <div>
+ <button {onclick}>{ "+1" }</button>
+ <p>{ *counter }</p>
+ </div>
}
}
fn main() {
yew::Renderer::<App>::new().render();
}
このようになりました。
ボタンをクリックすると数字が1ずつ増えていきます。
これで終わりなのもねえ……と思い、もう少しだけいじってみます。
地味な変更として、関数名がonclick
のときは<button {onclick}>
で済みましたが、名前を変えたので<button onclick={increment}>
にしないといけません。
use yew::prelude::*;
#[function_component]
fn App() -> Html {
let counter = use_state(|| 0);
- let onclick = {
+ let increment = {
let counter = counter.clone();
move |_| {
let value = *counter + 1;
counter.set(value);
}
};
+ let decrement = {
+ let counter = counter.clone();
+ move |_| {
+ let value = *counter - 1;
+ counter.set(value);
+ }
+ };
html! {
<div>
- <button {onclick}>{ "+1" }</button>
+ <button onclick={increment}>{ "+1" }</button>
+ <button onclick={decrement}>{ "-1" }</button>
<p>{ *counter }</p>
</div>
}
}
fn main() {
yew::Renderer::<App>::new().render();
}
ちゃんと動いています。
まだ若干物足りないので、スタイルもつけておきましょう。
とは言ってもYewではなくTrunkの範囲です。
まずはCSSファイルを作成します。
touch style.css
index.html
にCSSへのlinkを追加します。
通常はrel="stylesheet"
なのがrel="css"
なのに注意です。
また、data-trunk
属性が必要です。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <link data-trunk rel="css" href="style.css" />
<title>My first Yew</title>
</head>
<body></body>
</html>
あとは普通にスタイルを書けばOKです。
ただし、クラス名にハッシュがつくとかそういうのは無いので、それなりにちゃんとしたCSS設計が必要そうです。
TrunkにおけるCSSやSassファイルの追加の方法は以下のページに記載されています。
最後に
現段階ではRustらしいことは何もしていませんが、それでも途中やたらエラーが出ていました。
例えばdecrement
の関数を作成したけど、まだbutton
に適用していない段階では以下のエラーが表示されました。
|
17 | move |_| {
| ^
|
help: consider giving this closure parameter an explicit type
|
17 | move |_: _| {
| +++
今まで自分が書いてきたコードでは「定義してるのに未使用です」程度のエラーしか出なかったので驚いています。
体系的に理解するとまでいくと難しそうですが、RustでWebアプリケーションを作るのが当たり前になる日も来るかもしれませんから、素振りと思ってもう少し練習してみます。
最後まで読んでくださってありがとうございます!
Twitterでも情報を発信しているので、良かったらフォローお願いします!
Devトークでのお話してくださる方も募集中です!