topcoat — Wasm不要でリアクティブに動くRust製フルスタックWebフレームワーク
tokio-rs/topcoat
★ 6,826 ・ Rust ・ MIT
概要
Topcoat は、非同期ランタイム Tokio のエコシステム(tokio-rs)で開発されている、Rust 向けのフルスタック Web アプリケーションフレームワークです。「batteries-included(必要な機能が最初から揃っている)」を掲げており、シンプルさと開発者の生産性を重視して設計されています。
従来の Web 開発では、サーバー側の API 実装とクライアント側の SPA(Single Page Application)実装を別々に用意したり、Rust でフロントエンドを組むために WebAssembly(Wasm)のビルド環境を用意したりするのが一般的でした。Topcoat では、サーバーサイドでの HTML レンダリングを基本としつつ、必要な箇所だけ JavaScript に変換してブラウザ上で即座に実行するアプローチを採用しています。Rust の堅牢な型システムと非同期処理を活かしながら、余計なビルドステップや定型コードを減らして Web アプリケーションを開発したいエンジニアに向いています。
主な特徴
- Wasm バンドルやクライアントビルド不要のリアクティビティ: サーバー側で初期レンダリングを行いながら、
$(...)内の Rust 式を JavaScript に変換してブラウザ上で実行します。サーバーとの往復通信を行わずに即時反映されるインタラクティブな UI を構築できます。 - サーバーサイドの部分更新を担う
#[shard]: 検索結果の絞り込みなどサーバー処理が必要な更新には#[shard]属性を付与します。引数の変更を検知してサーバー上で再描画を行い、対象の HTML だけを自動で差し替えます。 - 直感的な
view!マクロと制御構文: HTML の構造の中に、通常の Rust のforループや式をそのまま埋め込んで記述できます。独自構文の習得コストが低く、Rust 標準のフロー制御を活用できます。 - モジュール構造に基づくルーティング: ファイルやモジュールの階層構造からルートツリーを自動で導出する
module_router!を備えています。特別なビルド手順を挟まずにファイルベースのルーティングが可能です。 - プロジェクト内に直接配置してカスタマイズできる Topcoat UI: shadcn/ui に着想を得た Tailwind CSS ベースの UI コンポーネント群が用意されています。CLI コマンドでコードをプロジェクト内にコピーし、用途に合わせて自由に改変できます。
- アセット管理と外部リソースの統合:
asset!マクロによりバイナリ内の参照を検知し、ハッシュ付き URL で配信やキャッシュを行います。Tailwind CSS のほか、Fontsource や Iconify との連携も標準で考慮されています。
使い方
プロジェクトの開始
README によると、CLI ツールの topcoat new コマンドを使ってアプリケーションの雛形を作成し、開発サーバーを起動する導入方法が用意されています。また、既存プロジェクトへ手動で依存関係を追加して最小構成を組むことも可能です。
基本的なコード例
最小限のアプリケーションコードは次のように記述します。Tokio の非同期ランタイム上で topcoat::start を呼び出して起動します。
use topcoat::{
Result,
context::Cx,
router::{module_router, page},
view::{View, component, view},
};
#[tokio::main]
async fn main() {
topcoat::start(module_router!().build()).await.unwrap();
}
#[page]
async fn home(cx: &Cx) -> Result<impl View> {
Ok(view! {
<!DOCTYPE html>
<html>
<body>
hello(name: "World")
</body>
</html>
})
}
#[component]
async fn hello(cx: &Cx, name: &str) -> Result<impl View> {
Ok(view! { "Hello, " (name) "!" })
}
クライアント側のインタラクションと部分更新
ブラウザ上だけで完結するリアクティブな状態変化は、signal と $(...) を使って表現します。このコードはサーバー上で評価されるだけでなく、JavaScript に変換されてブラウザ上でも動作します。
#[component]
async fn faq(cx: &Cx) -> Result<impl View> {
let open = signal(cx, || false);
Ok(view! {
// サーバーとの通信を行わず、ブラウザ上で動作する
<button @click=$(|_e| open.set(!open.get()))>"What is Topcoat?"</button>
"A full-stack Rust framework."
})
}
サーバー側での処理(データベース検索など)を伴うインタラクションには、#[shard] 属性を持つコンポーネントを組み合わせます。
#[component]
async fn search(cx: &Cx) -> Result<impl View> {
let query = signal(cx, String::new);
Ok(view! {
<input @input=$(|e: Event| query.set(e.target.value))>
// 入力値に応じてサーバー側で更新される
search_results(query: $(query.get()))
})
}
#[shard]
async fn search_results(cx: &Cx, query: String) -> Result<impl View> {
Ok(view! {
<ul>
// サーバー側の非同期処理(DB クエリなど)を実行
for product in search_products(cx, &query).await? {
<li>(product.name)</li>
}
</ul>
})
}
コードフォーマット
マクロ内のマークアップを含むコードベース全体の整形には、専用コマンド topcoat fmt を利用できます。
技術的なポイント
Rust 式の JavaScript トランスパイル
Topcoat の大きな特徴は、クライアント側の処理に Wasm の巨大なランタイムを同梱しない点です。$(...) で囲まれた式は通常の型チェックされた Rust コードとして扱われますが、Topcoat がこれを JavaScript に変換します。これにより、初期表示時はサーバーサイドで高速に HTML を組み立て、ユーザー操作時の細かな状態変化はブラウザ側で軽量に即座に実行するというハイブリッドな構成を実現しています。
ルーティングとモジュール構造の自動マッピング
module_router! マクロを使用すると、src/ 配下のファイル構造を元にルーティングテーブルが解決されます。たとえば src/app/about.rs は /about に、src/app/posts/id.rs は /posts/{post_id} に対応します。アンダースコアで始まるファイル(例: _marketing.rs)は URL セグメントを含まないレイアウト定義として機能し、api/health.rs のような API エンドポイントも同じルールで整理できます。
フルスタックを支える周辺機能
Web 開発に必要なプリミティブが最初からフレームワーク内に統合されています。
- コンテキスト(
Cx)とキャッシュ: リクエスト情報や型付けされた共有データへのアクセスを提供します。#[memoize]属性を用いることで、リクエスト単位でのキャッシュや重複呼び出しの排除が可能です。 - セッションと Cookie: 署名付き・暗号化 Cookie の読み書きや、ストレージ実装を差し替え可能なセッション認証(ログイン/ログアウト、有効期限の延長、トークンローテーション)が提供されています。
- レンダリング制御: 非同期データの読み込み中にフォールバックを表示する
suspenseや、レンダリング失敗を捕捉するerror_boundary、非同期処理の進行に合わせて HTML を差し替えるlive!/emit!などの仕組みが用意されています。 - アセットパイプライン:
asset!マクロで記述された静的アセットを検出し、ハッシュ付き URL で効率的なブラウザキャッシュを効かせた配信が可能です。
注意点
開発初期段階・実験的ステータス
README には「Early-stage and experimental. Expect breaking changes.」と明記されています。破壊的な変更が加わる可能性が高いため、本番環境への導入には十分な検証が必要です。
ライセンス
プロジェクトは MIT ライセンスのオープンソースソフトウェアとして公開されています。
クライアントコードの制約
$(...) による JavaScript 変換は軽量で直感的ですが、任意の複雑な Rust クレートやライブラリをクライアント側で動かせるわけではありません。ブラウザ側で実行可能な構文や機能の範囲については、ドキュメントの指示に従う必要があります。
まとめ
Topcoat は、Tokio プロジェクトから登場した、Rust による生産性の高いフルスタック Web 開発を目指すフレームワークです。サーバーサイドレンダリングを主軸としつつ、Wasm を使わずに軽量な JavaScript 変換でリアクティブな操作性を両立させている点が特徴です。現在も実験的段階にありますが、Rust の Web 開発エコシステムにおいて注目すべきアプローチのひとつです。





