Skip to content

Instantly share code, notes, and snippets.

@mizchi
Created July 17, 2025 08:53
Show Gist options
  • Save mizchi/224dbeaf953f190262fb6a48ef101d8a to your computer and use it in GitHub Desktop.
Save mizchi/224dbeaf953f190262fb6a48ef101d8a to your computer and use it in GitHub Desktop.

できたもの

image

Next.js 視点で leptos のチュートリアル https://book.leptos.dev/01_introduction.html でなぞって、評価して。


Leptos vs Next.js: Rust製WebフレームワークをNext.js開発者の視点で比較する

はじめに

Leptos は Rust で書かれたフルスタック Web フレームワークです。React/Next.js 開発者の視点から、Leptos の特徴と違いを比較してみましょう。

基本的な違い

言語とエコシステム

項目 Leptos Next.js
言語 Rust JavaScript/TypeScript
パッケージマネージャー Cargo npm/yarn/pnpm
ビルドツール cargo-leptos Webpack/Turbopack
型安全性 コンパイル時の完全な型チェック TypeScript による型チェック

アーキテクチャの哲学

Leptos: Fine-grained reactivity(細粒度リアクティビティ)

  • Solid.js に似たリアクティブシステム
  • 仮想 DOM を使わず、直接 DOM を更新
  • シグナルベースの状態管理

Next.js: 仮想 DOM ベース

  • React の仮想 DOM による差分更新
  • useState/useReducer による状態管理
  • React Server Components による新しいアプローチ

レンダリング方式の比較

SSR(サーバーサイドレンダリング)

Leptos:

  • cargo-leptos による統合ツール
  • 非同期レンダリングと複数の SSR モード
  • ハイドレーションバグへの対策が組み込まれている

Next.js:

  • getServerSideProps や App Router の Server Components
  • ISR(Incremental Static Regeneration)のサポート
  • Edge Runtime での実行可能

CSR(クライアントサイドレンダリング)

両フレームワークとも CSR をサポートしていますが、アプローチが異なります:

Leptos:

// Leptos のリアクティブな例
let (count, set_count) = create_signal(0);
view! {
    <button on:click=move |_| set_count.update(|n| *n += 1)>
        "Count: " {count}
    </button>
}

Next.js:

// Next.js (React) の例
const [count, setCount] = useState(0);
return (
    <button onClick={() => setCount(count + 1)}>
        Count: {count}
    </button>
);

ルーティングの比較

Leptos のルーティング

  • URL のパスとクエリを中心に設計
  • グローバル状態管理の中核として機能
  • 動的ルーティングとネストルーティングをサポート

Next.js のルーティング

  • ファイルシステムベースのルーティング
  • App Router では layouts と loading 状態の組み込みサポート
  • 並列ルートとインターセプトルートなどの高度な機能

データフェッチングの比較

Leptos

  • Server Functions による型安全な RPC
  • Resources と Suspense による非同期データ処理
  • Rust の型システムによる完全な型安全性

Next.js

  • fetch API with caching
  • Server Actions (App Router)
  • API Routes による柔軟なバックエンド実装

パフォーマンスの観点

Leptos の利点

  • WASM によるネイティブに近いパフォーマンス
  • Fine-grained reactivity による最小限の DOM 更新
  • コンパイル時の最適化

Next.js の利点

  • JavaScript エコシステムの成熟した最適化ツール
  • 自動的なコード分割とプリフェッチ
  • Edge Runtime での軽量実行

開発体験の比較

Leptos

// 型安全性が言語レベルで保証される
#[component]
fn App() -> impl IntoView {
    view! {
        <h1>"Hello, Leptos!"</h1>
    }
}

Next.js

// TypeScript による型チェック
export default function App() {
    return <h1>Hello, Next.js!</h1>
}

どちらを選ぶべきか?

Leptos が適している場合

  • Rust エコシステムを活用したい
  • 最大限の型安全性とパフォーマンスが必要
  • Fine-grained reactivity のモデルを好む
  • WASM の利点を活かしたい

Next.js が適している場合

  • JavaScript/TypeScript のエコシステムを活用したい
  • 豊富なサードパーティライブラリが必要
  • チームが React に精通している
  • Vercel のエコシステムを活用したい

まとめ

Leptos は Rust の強力な型システムとパフォーマンスを Web 開発に持ち込む野心的なフレームワークです。Next.js 開発者にとっては、学習曲線は急ですが、型安全性とパフォーマンスの面で大きなメリットがあります。

特に、以下のような場合は Leptos の採用を検討する価値があります:

  • 高パフォーマンスが要求されるアプリケーション
  • Rust でフルスタック開発を行いたい場合
  • Fine-grained reactivity のモデルに興味がある場合

一方で、既存の JavaScript エコシステムとの統合や、チームのスキルセットを考慮すると、多くの場合 Next.js の方が実用的な選択となるでしょう。

両フレームワークとも活発に開発が進んでおり、Web 開発の未来を形作る重要な技術です。プロジェクトの要件とチームの状況に応じて、適切な選択をすることが重要です。

use leptos::*;
#[component]
fn App() -> impl IntoView {
let (count, set_count) = create_signal(0);
let (name, set_name) = create_signal("World".to_string());
view! {
<div class="container">
<h1>"Hello, Leptos!"</h1>
<p>"これは Leptos で作成されたシンプルなアプリケーションです。"</p>
<div>
<h2>"カウンター"</h2>
<div class="counter">
"現在のカウント: " {move || count.get()}
</div>
<button on:click=move |_| set_count.update(|n| *n += 1)>
"増やす"
</button>
<button on:click=move |_| set_count.update(|n| *n -= 1)>
"減らす"
</button>
<button on:click=move |_| set_count.set(0)>
"リセット"
</button>
</div>
<div style="margin-top: 40px;">
<h2>"名前の入力"</h2>
<input
type="text"
on:input=move |ev| {
set_name.set(event_target_value(&ev));
}
prop:value=move || name.get()
placeholder="名前を入力"
style="padding: 8px; font-size: 16px; margin-right: 10px;"
/>
<p>"こんにちは、" {move || name.get()} "さん!"</p>
</div>
<div style="margin-top: 40px;">
<h2>"条件付きレンダリング"</h2>
{move || {
if count.get() > 5 {
view! { <p style="color: green;">"カウントが5を超えました!"</p> }
} else if count.get() < 0 {
view! { <p style="color: red;">"カウントが負の値です!"</p> }
} else {
view! { <p>"カウントは0から5の間です。"</p> }
}
}}
</div>
</div>
}
}
fn main() {
console_error_panic_hook::set_once();
mount_to_body(App);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment