Skip to content

Commit

Permalink
website version 0.20
Browse files Browse the repository at this point in the history
  • Loading branch information
hamza1311 committed Nov 24, 2022
1 parent 76eb791 commit 41c1bc5
Show file tree
Hide file tree
Showing 119 changed files with 11,437 additions and 1 deletion.
@@ -0,0 +1,8 @@
---
title: How it works
description: Low level details about the framework
---

# 低レベルなライブラリの中身

コンポーネントのライフサイクルの状態機械、VDOM の異なるアルゴリズム
@@ -0,0 +1,171 @@
---
title: Optimizations
description: Make your app faster
---

# 最適化とベストプラクティス

## neq_assign

親コンポーネントから props を受け取った際、`change`メソッドが呼ばれます。
これはコンポーネントの状態を更新することができるのに加え、コンポーネントが props が変わった際に再レンダリングするかどうかを決める
`ShouldRender`という真偽値を返すことができます。

再レンダリングはコストがかかるもので、もし避けられるのであれば避けるべきです。
一般的なルールとして props が実際に変化した際にのみ再レンダリングすれば良いでしょう。
以下のコードブロックはこのルールを表しており、props が前と変わったときに`true`を返します。

```rust
use yew::ShouldRender;

#[derive(PartialEq)]
struct ExampleProps;

struct Example {
props: ExampleProps,
};

impl Example {
fn change(&mut self, props: ExampleProps) -> ShouldRender {
if self.props != props {
self.props = props;
true
} else {
false
}
}
}
```

しかし我々は先に進んでいけます!
この 6 行のボイラープレードは`PartialEq`を実装したものにトレイトとブランケットを用いることで 1 行のコードへと落とし込むことができます。
[こちら](https://docs.rs/yewtil/*/yewtil/trait.NeqAssign.html)にて`yewtil`クレートの`NewAssign`トレイトを見てみてください。

## 効果的にスマートポインタを使う

**注意: このセクションで使われている用語がわからなければ Rust book は
[スマートポインタについての章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)
があり、非常に有用です。**

再レンダリングの際に props を作るデータを大量にコピーしないために、スマートポインタを用いてデータ自体ではなくデータへの参照だけを
コピーできます。
props や子コンポーネントで関連するデータに実データではなく参照を渡すと、子コンポーネントでデータを変更する必要がなければ
データのコピーを避けることができます。
その際、`Rc::make_mut`によって変更したいデータの変更可能な参照を得ることができます。

これにより、props が変更されたときにコンポーネントが再レンダリングされるかどうかを決めるかで`Component::change`に更なる恩恵があります。
なぜなら、データの値を比較する代わりに元々のポインタのアドレス (つまりデータが保管されている機械のメモリの場所) を比較できるためです。
2 つのポインターが同じデータを指す場合、それらのデータの値は同じでなければならないのです。
ただし、その逆は必ずしも成り立たないことに注意してください!
もし 2 つのポインタが異なるのであれば、そのデータは同じである可能性があります。
この場合はデータを比較するべきでしょう。

この比較においては`PartialEq`ではなく`Rc::ptr_eq`を使う必要があります。
`PartialEq`は等価演算子`==`を使う際に自動的に使われます。
Rust のドキュメントには[`Rc::ptr_eq`についてより詳しく書いてあります](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)

この最適化は`Copy`を実装していないデータの型に対して極めて有効なものです。
もしデータを簡単に変更できるのであれば、スマートポインタに取り換える必要はありません。
しかし`Vec``HashMap``String`などのような重たいデータの構造体に対してはスマートポインタを使うことで
パフォーマンスを改善することができるでしょう。

この最適化は値がまだ一度も子によって更新されていない場合に極めて有効で、親からほとんど更新されない場合においてもかなり有効です。
これにより、`Rc<_>s`が純粋なコンポーネントに対してプロパティの値をラップする良い一手となります。

## View 関数

コードの可読性の理由から`html!`の部分を関数へと移植するのは意味があります。
これは、インデントを減らすのでコードを読みやすくするだけでなく、良いデザインパターンを産むことにも繋がるのです。
これらの関数は複数箇所で呼ばれて書くべきコード量を減らせるため、分解可能なアプリケーションを作ることができるのです。

## 純粋なコンポーネント

純粋なコンポーネントは状態を変化せず、ただ中身を表示してメッセージを普通の変更可能なコンポーネントへ渡すコンポーネントのことです。
View 関数との違いとして、純粋なコンポーネントは式の構文\(`{some_view_function()}`\)ではなく
コンポーネントの構文\(`<SomePureComponent />`\)を使うことで`html!`マクロの中で呼ばれる点、
そして実装次第で記憶され (つまり、一度関数が呼ばれれば値は"保存"され、
同じ引数でもう一度呼ばれても値を再計算する必要がなく最初に関数が呼ばれたときの保存された値を返すことができる)、
先述の`neq_assign`ロジックを使う別々の props で再レンダリングを避けられる点があります。

Yew は純粋な関数やコンポーネントをサポートしていませんが、外部のクレートを用いることで実現できます。

## 関数型コンポーネント (a.k.a フック)

関数型コンポーネントはまだ開発中です!
開発状況については[プロジェクトボード](https://github.com/yewstack/yew/projects/3)に詳しく書いてあります。

## キー付き DOM ノード

## ワークスペースでコンパイル時間を減らす

間違いなく Yew を使う上での最大の欠点はコンパイルに時間がかかる点です。
プロジェクトのコンパイルにかかる時間は`html!`マクロに渡されるコードの量に関係しています。
これは小さなプロジェクトにはそこまで問題ないようですが、大きなアプリではコードを複数クレートに分割することでアプリに変更が加られた際に
コンパイラの作業量を減らすのが有効です。

一つ可能なやり方として、ルーティングとページ洗濯を担当するメインのクレートを作り、それぞれのページに対して別のクレートを作ることです。
そうして各ページは異なるコンポーネントか、`Html`を生成する大きな関数となります。
アプリの異なる部分を含むクレート同士で共有されるコードはプロジェクト全体で依存する分離したクレートに保存されます。
理想的には 1 回のコンパイルでコード全てを再ビルドせずメインのクレートかどれかのページのクレートを再ビルドするだけにすることです。
最悪なのは、"共通"のクレートを編集して、はじめに戻ってくることです:
共有のクレートに依存している全てのコード、恐らく全てのコードをコンパイルすることです。

もしメインのクレートが重たすぎる、もしくは深くネストしたページ (例えば別ページのトップでレンダリングされるページ)
で速く繰り返したい場合、クレートの例を用いてメインページの実装をシンプルにしたりトップで動かしているコンポーネントをレンダリングできます。

## バイナリサイズを小さくする

- Rust のコードを最適化する
- `cargo.toml` \( release profile を定義 \)
- `wasm-opt`を用いて wasm のコードを最適化する

**注意: バイナリサイズを小さくするのについては[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)に詳しく書いてあります。**

### Cargo.toml

`Cargo.toml``[profile.release]`のセクションに設定を書き込むことでリリースビルドを小さくすることが可能です。

```text
[profile.release]
# バイナリに含むコードを少なくする
panic = 'abort'
# コードベース全体での最適化 ( 良い最適化だがビルドが遅くなる)
codegen-units = 1
# サイズの最適化( よりアグレッシブに )
opt-level = 'z'
# サイズの最適化
# opt-level = 's'
# プログラム全体の分析によるリンク時最適化
lto = true
```

### wasm-opt

更に`wasm`のコードのサイズを最適化することができます。

The Rust Wasm Book には Wasm バイナリのサイズを小さくすることについてのセクションがあります:
[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)

- `wasm-pack`でデフォルトの`wasm`のコードをリリースビルド時に最適化する
- `wasm-opt`によって直接`wasm`ファイルを最適化する

```text
wasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm
```

#### yew/examples/にある例を小さなサイズでビルドする

注意: `wasm-pack`は Rust と Wasm のコードへの最適化を組み合わせます。`wasm-bindgen`はこの例では Rust のサイズ最適化を用いていません。

| 使用したツール | サイズ |
| :-------------------------- | :----- |
| wasm-bindgen | 158KB |
| wasm-bindgen + wasm-opt -Os | 116KB |
| wasm-pack | 99 KB |

## 参考文献:

- [The Rust Book のスマートポインタに関する章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)
- [the Rust Wasm Book でのバイナリサイズを小さくすることについて](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)
- [Rust profiles についてのドキュメント](https://doc.rust-lang.org/cargo/reference/profiles.html)
- [binaryen プロジェクト](https://github.com/WebAssembly/binaryen)
@@ -0,0 +1,35 @@
---
title: Callbacks
description: ComponentLink and Callbacks
---

”リンク”コンポーネントはコンポーネントがコールバックを登録できて自身を更新することができるメカニズムです。

## ComponentLink API

### callback

実行時にコンポーネントの更新メカニズムにメッセージを送信するコールバックを登録します。
これは、渡されたクロージャから返されるメッセージで `send_self` を呼び出します。
`Fn(IN) -> Vec<COMP::Message>`が渡され、`Callback<IN>`が返されます。

### send_message

現在のループが終了した直後にコンポーネントにメッセージを送信し、別の更新ループを開始します。

### send_message_batch

実行時に一度に多数のメッセージを一括して送信するコールバックを登録します。
メッセージによってコンポーネントが再レンダリングされる場合、バッチ内のすべてのメッセージが処理された後、コンポーネントは再レンダリングされます。
`Fn(IN) -> COMP::Message`が渡され、`Callback<IN>`が返されます。

## コールバック

_\(This might need its own short page.\)_

コールバックは、Yew 内のサービス、エージェント、親コンポーネントとの通信に使われます。
これらは単に `Fn``Rc` でラップしただけであり、クローンを作成できるようにするためのものです。

これらの関数には `emit` 関数があり、`<IN>` 型を引数に取り、それをアドレスが欲しいメッセージに変換します。
親からのコールバックが子コンポーネントに props で提供されている場合、子は `update` ライフサイクルフックで `emit` をコールバックに呼び出して親にメッセージを返すことができます。
マクロ内で props として提供されたクロージャや関数は自動的にコールバックに変換されます。

0 comments on commit 41c1bc5

Please sign in to comment.