7月22日、Tokio.rsが「Announcing Topcoat: a framework for building full-stack reactive web apps with Rust」と題した記事を公開した。
RustでWebアプリのフロントエンドを書こうとすると、これまではLeptosやDioxusのようなWebAssembly(WASM)ベースのフレームワークが主な選択肢だった。しかしWASMにはバンドルサイズの肥大化やクライアント/サーバー間のデータシリアライゼーションの煩雑さという課題がある。Tokioチームが今回発表したTopcoatは、RustのサブセットをJavaScriptにクロスコンパイルするマクロを用いることで、WASMを一切使わずにリアクティブなUIを実現するフルスタックフレームワークだ。
WebAssembly不要のリアクティビティとは何か
Topcoatの基本アーキテクチャは完全サーバーサイドレンダリング(SSR)だ。ただし「SSRだからクライアント側の操作はすべてサーバーへのラウンドトリップが発生する」というわけではない。
Topcoatではview!マクロ内にシグナル(signal)と@clickや:hiddenなどのバインディングを書くと、そのロジック部分がコンパイル時にJavaScriptへ変換される。ボタンクリックによる表示/非表示の切り替えのような軽量なインタラクションは、生成されたJavaScriptがブラウザ上で直接処理するため、サーバーへの通信が発生しない。
view! {
signal open = false;
<button
@click=$(|_e| open.set(!open.get()))
>
"What is Topcoat?"
</button>
<p :hidden=$(!open.get())>"A fullstack Rust framework."</p>
}
一方、クライアントの状態変化に応じてDBを参照するような処理は、UIの必要な部分だけをサーバーで再レンダリングして差分を差し替える。下記は検索入力に連動してサーバー側でクエリを実行し、結果リストを更新する例だ。コンポーネントがasyncであるため、DBアクセスやパーミッション検証をそのままコンポーネント内に書ける。
async fn search() -> Result {
view! {
signal query = String::new();
<input @input=$(|e: Event| query.set(e.target.value))>
search_results(query: $(query.get()))
}
}
async fn search_results(cx: &Cx, query: String) -> Result {
view! {
<ul>
for product in search_products(cx, &query).await? {
<li>(product.name)</li>
}
</ul>
}
}
クライアント側リアクティビティが成熟するまでの代替手段として、HTMXやAlpine.jsとの統合も用意されている。
なぜTokioがWebフレームワークを作るのか
記事の「動機」の説明が興味深い。著者はTokioConf(動画)で「RustはグリーンフィールドWebアプリ(=新規開発プロジェクト)においてトップ3言語になりうる」と予測していたという。
その根拠はAIの登場だ。AIコーディング補助ツールの開発速度を左右するのはプログラミング言語の習熟度よりも利用可能なライブラリの充実度であり、Rustを書いたことのない経験豊富なエンジニアでも初日からAIと協働してRustで開発を進められる事例を著者は目撃しているという。言語間の生産性差がAIによって縮小しているという分析だ。
また、すでにRustを採用している組織では、社内ライブラリやビルドシステムがRust中心に構築されており、高レベルのWebアプリにも同じ言語スタックを使いたいという実用的な需要があると指摘している。
こうした背景のもと、Tokioチームは「Rustのエコシステムにbatteries-included(必要なものがすべて揃った)な状態を整備する」という方針を進めている。2026年4月にはRust向けORM(オブジェクト関係マッピングライブラリ)「Toasty」をリリースしており、TopcoatはそのUIレイヤーに相当する次のピースとなる。
設計思想:「局所性(Locality of behavior)」
Topcoatの設計はReactに近い部分を持ちながら、コンポーネントが自身でデータを取得することを推奨する点で独自路線を取る。データはpropsで受け取るより、コンポーネント内で直接fetchする設計だ。
async fn user_profile(cx: &Cx, user_id: &str) -> Result {
let user = load_user(cx, user_id).await?;
view! {
<h1>(user.name)</h1>
...
}
}
重複取得を防ぐため、Reactのcacheに着想を得たリクエストレベルのメモ化が組み込まれている。認証も同様に、コンポーネント内で直接require_authを呼ぶ形にでき、ミドルウェアへの依存を減らせる。記事中では「Reactのルールに縛られないフック」という表現でこの設計が説明されている。
UIツールチェーンの整備とAxumとの関係
アセットパイプライン、Fontsource・Iconifyとの統合、Tailwind CSSベースのコンポーネントライブラリ(shadcn/uiに着想を得た、ソースコードをプロジェクトに直接コピーして改変可能な形式)など、UI開発に必要な一通りのツールが同梱されている。
同じくTokioが管理するHTTPフレームワークAxumとの関係については、記事が明確に整理している。AxumはHTTP APIエンドポイント向けの低レベルHTTPルーターであり、TopcoatはそのボイラープレートをWebアプリ開発に特化して取り除くレイヤーだ。両者は競合せず、同一プロジェクト内での併用を想定した設計になっている。
現状と今後のロードマップ
初回リリースのため、クライアントサイドのリアクティビティシステムはまだ開発初期段階にある。現時点では複雑なクライアント状態の管理や、シグナル間の依存関係に関する表現力に制限があり、HTMX・Alpine.jsとの統合はその補完手段として位置づけられている。ロードマップにはToastyとのより深い統合、バリデーション、メール機能などが挙げられている。フィードバックはTokio Discordの#topcoatチャンネルで受け付けている。
詳細はAnnouncing Topcoat: a framework for building full-stack reactive web apps with Rustを参照していただきたい。