leptos - Rust で高速なウェブアプリケーションを構築します。

(Build fast web applications with Rust.)

Created at: 2022-08-01 04:40:30
Language: Rust
License: MIT

ご注意:このフレームワークは活発に開発中です。現時点では0.0.xリリースのサイクルで保持しており、0.1.0の準備ができていないことを示しています。ドキュメントと機能に関する活発な作業が行われており、APIは必ずしも安定していると見なされるべきではありません。同時に、それはおもちゃのプロジェクトや概念実証以上のものであり、私は自分のアプリケーション開発に積極的に使用しています。

レプトス ロゴ

crates.io docs.rs 不和

レプトス

use leptos::*;

#[component]
pub fn SimpleCounter(cx: Scope, initial_value: i32) -> Element {
    // create a reactive signal with the initial value
    let (value, set_value) = create_signal(cx, initial_value);

    // create event handlers for our buttons
    // note that `value` and `set_value` are `Copy`, so it's super easy to move them into closures
    let clear = move |_| set_value(0);
    let decrement = move |_| set_value.update(|value| *value -= 1);
    let increment = move |_| set_value.update(|value| *value += 1);

    // this JSX is compiled to an HTML template string for performance
    view! {
        cx,
        <div>
            <button on:click=clear>"Clear"</button>
            <button on:click=decrement>"-1"</button>
            <span>"Value: " {move || value().to_string()} "!"</span>
            <button on:click=increment>"+1"</button>
        </div>
    }
}

// Easy to use with Trunk (trunkrs.dev) or with a simple wasm-bindgen setup
pub fn main() {
    mount_to_body(|cx| view! { cx,  <SimpleCounter initial_value=3 /> })
}

フレームワークについて

Leptos は、フルスタックの同型 Rust ウェブフレームワークで、きめ細かな反応性を活用して宣言型のユーザーインターフェイスを構築します。

それはどういう意味ですか。

  • フルスタック: Leptos を使用して、ブラウザー (クライアント側レンダリング)、サーバー上 (サーバーレンダリング)、またはサーバー上で HTML をレンダリングしてからブラウザーで対話機能を追加する (ハイドレーション) で実行されるアプリを構築できます。これには、データと HTML (コンポーネントの順不同ストリーミング) の両方のHTTP ストリーミングのサポートが含まれます。
    Resource
    <Suspense/>
  • 同型:Leptosは、同型サーバー関数、つまりクライアントまたはサーバー上で「同じ形状」で呼び出すことができるが、サーバー上でのみ実行される関数を記述するためのプリミティブを提供します。つまり、サーバーのみのロジック (データベース要求、認証など) を、それを使用するクライアント側コンポーネントと一緒に記述し、ブラウザーで実行されているかのようにサーバー関数を呼び出すことができます。
  • ウェブ:レプトスはウェブプラットフォームとウェブ標準に基づいて構築されています。ルーターは、Webの基本(リンクやフォームなど)を使用し、それらを置き換えようとするのではなく、それらの上に構築するように設計されています。
  • フレームワーク:Leptosは、リアクティブシステム、テンプレートライブラリ、サーバー側とクライアント側の両方で動作するルーターなど、最新のWebアプリを構築するために必要なほとんどのものを提供します。
  • きめ細かな反応性: フレームワーク全体がリアクティブ プリミティブから構築されます。これにより、最小限のオーバーヘッドで非常にパフォーマンスの高いコードが可能になります:リアクティブ信号の値が変更された場合、他のコードを実行せずに、単一のテキストノードを更新したり、1つのクラスを切り替えたり、DOMから要素を削除したりできます。(したがって、仮想DOMはありません!)
  • 宣言型:Leptosにページの外観を伝え、フレームワークにブラウザにその方法を指示させます。

詳細情報

Leptosについてもっと学ぶためのいくつかのリソースがあります:

nightly
手記

ほとんどの例は、あなたが使用していることを前提としています Rust.安定版 (stable) を使用している場合は、次の点に注意してください。

nightly

  1. を有効にする必要がありますフラグ:
    "stable"
    Cargo.toml
    leptos = { version = "0.0", features = ["stable"] }
  2. nightly
    シグナルにアクセスして設定するための関数呼び出し構文を有効にします。ご利用の場合は、 あなたはただ電話します、、または手動で。正しい API の例については、カウンタ安定版の例を確認してください。
    stable
    .get()
    .set()
    .update()

ベンチマーク

サーバー側のレンダリング

サーバー上のLeptosのHTMLレンダリングをTeraYewSycamoreと比較するベンチマークを作成しました。ここでベンチマークを見つけて、自分で実行できます。LeptosはHTMLをTeraとほぼ同じ速さでレンダリングし、テンプレートが大きくなるにつれて適切にスケーリングされます。これは、同様のフレームワークによって行われるサーバー側のHTMLレンダリングよりも大幅に高速です。

cargo bench

クリックして結果を表示
ns/iter テラ レプトス プラタナス
3 カウンター 3,454 5,666 34,984 32,412
TodoMVC (todos なし) 2,396 5,561 38,725 68,749
TodoMVC (1000 todos) 3,829,447 3,077,907 5,125,639 19,448,900
平均 1.08 1.65 6.25 9.36

クライアント側レンダリング

フロントエンドWebフレームワークの生のレンダリングパフォーマンスをテストするためのゴールドスタンダードは、js-framework-benchmarkです。公式の結果には、Leptosが最速のRust / Wasmフレームワークとしてリストされており、SolidJSよりもわずかに遅く、Svelte、Preact、Reactなどの一般的なJSフレームワークよりも大幅に高速です。

クリックして結果を表示 JS-フレームワーク-ベンチマーク結果

御意見・御感想

これをネイティブGUIに使用できますか?

もちろん!明らかにマクロはDOMノードを生成するためのものですが、リアクティブシステムを使用して、DOMと同じ種類のオブジェクト指向のイベントコールバックベースのフレームワークを使用するGUIツールキットをネイティブに簡単に駆動できます。原則は同じです。

view

  • 信号、派生信号、メモを使用して反応型システムを作成
  • GUI ウィジェットを作成する
  • イベントリスナーを使用してシグナルを更新する
  • UI を更新する効果を作成する

私は非常に簡単なGTKの例をまとめたので、私が何を意味するのかがわかります。

これはイチイ/ダイオクサスとどう違うのですか?

表面的には、これらのライブラリは似ているように見えるかもしれません。もちろん、YewはWeb UI開発のための最も成熟したRustライブラリであり、巨大なエコシステムを持っています。ダイオクサスは多くの点で似ており、Reactに大きく影響を受けています。Leptosとこれらのフレームワークの概念的な違いは次のとおりです。

  • VDOMときめ細かな比較:Yew は仮想 DOM (VDOM) モデルに基づいて構築されており、状態が変化するとコンポーネントが再レンダリングされ、新しい仮想 DOM ツリーが生成されます。Yew はこれを以前の VDOM と照合し、それらのパッチを実際の DOM に適用します。コンポーネント関数は、状態が変化するたびに再実行されます。レプトスはまったく異なるアプローチを取ります。コンポーネントは一度実行され、実際のDOMノードを作成(および返し)し、それらのDOMノードを更新するようにリアクティブシステムを設定します。
  • パフォーマンス:これはパフォーマンスに大きな影響を与えます:Leptosは、YewよりもUIの作成と更新の両方ではるかに高速です。
  • メンタルモデル:きめ細かな反応性を採用すると、メンタルモデルも単純化される傾向があります。再レンダリングがないため、驚くべきコンポーネントの再レンダリングはありません。アプリは、パフォーマンスに影響しないため、アプリにとって意味のあるものに基づいてコンポーネントに分割できます。

これはシカモアとどう違うのですか?

概念的には、これら 2 つのフレームワークは非常に似ています: どちらもきめ細かい反応性に基づいて構築されているため、ほとんどのアプリは 2 つの間で非常によく似ており、Sycamore または Leptos アプリはどちらも SolidJS アプリによく似ています。

大きな違いを生むいくつかの実際的な違いがあります。

  • 成熟:Sycamoreは明らかに、より大きなエコシステムを備えたはるかに成熟した安定したライブラリです。
  • テンプレート:レプトスはJSXのようなテンプレートフォーマット(syn-rsx上に構築)をマクロに使用します。Sycamoreは、独自のテンプレートDSLまたはビルダー構文の選択肢を提供します。
    view
  • テンプレートノードのクローン作成:Leptosのマクロは、静的なHTML文字列とそのリアクティブ値を割り当てる方法の一連の命令にコンパイルされます。これは、実行時に、LeptosがDOMノードを作成するのではなく、アノードのクローンを作成できることを意味します。これは、コンポーネントをレンダリングする非常に高速な方法です。
    view
    <template>
    document.createElement()
  • 読み取り/書き込み分離:Leptosは、Solidと同様に、シグナルゲッターとセッターの間の読み取り/書き込み分離を促進するため、次のようなタプルでシグナルにアクセスすることになります(必要に応じて、またはAPIにとってより便利な場合は、create_rw_signalを使用して統一された読み取り/書き込みシグナルを提供できます)。
    let (count, set_count) = create_signal(cx, 0);
  • 信号は関数です:Leptosでは、特定のメソッドを呼び出すのではなく、シグナルを呼び出してアクセスすることができます(そう、代わりに) これにより、より一貫性のあるメンタルモデルが作成されます:リアクティブ値へのアクセスは常に関数を呼び出すことの問題です。例えば:
    count()
    count.get()
let (count, set_count) = create_signal(cx, 0); // a signal
let double_count = move || count() * 2; // a derived signal
let memoized_count = create_memo(cx, move |_| count() * 3); // a memo
// all are accessed by calling them
assert_eq!(count(), 0);
assert_eq!(double_count(), 0);
assert_eq!(memoized_count(), 0);

// this function can accept any of those signals
fn do_work_on_signal(my_signal: impl Fn() -> i32) { ... }
  • シグナルとスコープは静的です。LeptosとSycamoreはどちらも、クロージャ(特にイベントリスナー)で信号を動かす苦痛を和らげ、RustUIコードで非常に馴染みのある信号を回避します。Sycamoreは、バンプ割り当てを使用してシグナルの有効期間をスコープに結び付けることによってこれを行います:参照はクロージャに移動できます。Leptosは、アリーナの割り当てを使用し、インデックスを回すことによってこれを行います:、のようなタイプは、実際にはインデックスをアリーナにラッパーします。これは、スコープとシグナルの両方がボタンディンレプトスであることを意味し、生涯の複雑さを追加することなく、クロージャに簡単に移動できることを意味します。
    Copy
    { let count = count.clone(); move |_| ... }
    Copy
    &'a Signal<T>
    ReadSignal<T>
    WriteSignal<T>
    Memo<T>
    Copy
    'static