Help us understand the problem. What is going on with this article?

[Kagura] Rustでフロントエンドフレームワークを作ってみた。

概要

Rustをwasmにコンパイルすることで利用可能なフロントエンドフレームワークを作ってみました。なお、フロントエンド用のクレートだとYewというものがすでに存在しています。

c.f. Yew

インストール

ドキュメントコメントを全然付けていないのと開発途上も良いところなので、まだCrates.ioには公開していません。githubからcloneして使うことになります。

Crates.ioに公開しました。

Kaguraのgithubリポジトリ

使い方

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にバインドします。updateMsgをもとに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の差分レンダリングをコンポーネント単位で行っているため無駄が多いです。

今後の予定

  1. タグ・属性・イベントの対応数を増やす
  2. 仮想DOMのレンダリングを高速化(せめてタグ単位で差分を取る)
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした