概要
Rustをwasmにコンパイルすることで利用可能なフロントエンドフレームワークを作ってみました。なお、フロントエンド用のクレートだとYewというものがすでに存在しています。
c.f. Yew
インストール
ドキュメントコメントを全然付けていないのと開発途上も良いところなので、まだCrates.ioには公開していません。githubからcloneして使うことになります。
Crates.ioに公開しました。
使い方
kagura::Component::new(initial_state, update, render)
によってコンポーネントを作ってkagura::run(component, id)
でエントリーポイントのidとルートコンポーネントを指定すれば良いです。
hello world の例を示します。
extern crate kagura;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(start)]
pub fn main() {
kagura::run(kagura::Component::new(State, update, render), "app");
}
struct State;
struct Msg;
fn update(_: &mut State, _: &Msg) {}
fn render(_: &State) -> kagura::Html<Msg> {
use kagura::Html;
use kagura::Attributes;
use kagura::Events;
Html::h1(
Attributes::new(),
Events::new(),
vec![
Html::unsafe_text("hello kagura"),
],
)
}
State
がコンポーネントの状態を表現し、Msg
がイベントをupdate
にバインドします。update
でMsg
をもとにState
を更新し、State
に基づきrender
でビューを作るという構造を取ります。(要はTEA)
あくまでコンポーネント指向なので、コンポーネントのレンダーからさらに別のコンポーネントを呼び出すことができます。呼び出されたコンポーネントのステートは呼び出し元のステートが変わらない限りリセットされません。
現状、子コンポーネントから親コンポーネントにイベントを伝搬するまともな方法が無いので、あまりコンポーネント指向としての意味を成していません。(今後対応します)
subscribeで親コンポーネントにメッセージを伝搬できるようになりました。
以下に子コンポーネントを使用する例を示します。
extern crate kagura;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(start)]
pub fn main() {
kagura::run(kagura::Component::new(State, update, render), "app");
}
struct State;
struct Msg;
fn update(_: &mut State, _: &Msg) {}
fn render(_: &State) -> kagura::Html<Msg> {
use kagura::Html;
use kagura::Attributes;
use kagura::Events;
Html::div(
Attributes::new()
.with_style("color: red;"),
Events::new(),
vec![
Html::component(child::new()),
Html::component(child::new()),
Html::component(child::new()),
Html::component(child::new()),
],
)
}
mod child {
pub fn new() -> kagura::Component<Msg, State> {
kagura::Component::new(0, update, render)
}
pub type State = u64;
pub enum Msg {
CountUp,
}
fn update(state: &mut State, msg: &Msg) {
match msg {
Msg::CountUp => {*state += 1;}
}
}
fn render(state: &State) -> kagura::Html<Msg> {
use kagura::Events;
use kagura::Attributes;
use kagura::Html;
Html::h1(
Attributes::new(),
Events::new()
.with_on_click(|| {Msg::CountUp}),
vec![Html::unsafe_text(state.to_string())],
)
}
}
onClickイベントは() -> Msg
なクロージャでMsg
にマップしています。もし、子コンポーネントの初期状態を親コンポーネントから指定したければ、child::new()
の引数を用いることになります。
実装状況
現状、タグ・属性の一部とonClickイベントにしか対応できていません。また、仮想DOMの差分レンダリングをコンポーネント単位で行っているため無駄が多いです。
今後の予定
- タグ・属性・イベントの対応数を増やす
- 仮想DOMのレンダリングを高速化(せめてタグ単位で差分を取る)