🌊 ReactとSvelte、両方の「中の人」が作った新フレームワーク「Ripple」を眺める
React Hooksに関わりSvelte 5のコンパイラを主導したDominic Gannawayの新作Ripple。track()と@演算子によるコンパイラ駆動リアクティビティの野心と、α版の現実を整理する。
Dominic Gannawayという名前にピンと来なくても、この人が触ってきたコードには全員お世話になっている。高速Reactクローン「Inferno」の作者。MetaではReact Hooksの開発とテキストエディタ基盤Lexicalに関わり、その後SvelteのコアチームでSvelte 5のコンパイラアーキテクチャを主導した。
ReactとSvelte、対立する二大思想の両方を内側から書いた人が、「ゼロから設計し直したら何ができるか」で作ったのが「Ripple」だ。日本語の記事はZennに2件だけ。Qiitaはゼロ。せっかくなので早めに眺めておくことにした。
track()と@ — 依存配列のない世界
Rippleの核はコンパイラ駆動のfine-grained reactivityだ。リアクティブな値は track() で作り、@ を付けて読み書きする。
import { track } from 'ripple';
export function Counter() {
let count = track(0);
return (
<button @click={() => @count++}>
Count: {@count}
</button>
);
}
Reactでいうところの useState + useMemo + 依存配列の管理が、まるごと消える。コンパイラが「どのDOMノードがどの値に依存しているか」を静的に把握し、変更時にそのノードだけを直接更新する。仮想DOMは無い。配列も #[] と書けばTrackedArrayになり、push などの直接ミューテーションがそのままUIに反映される。
なお、α版につき構文はまだ動いている。実際、フィードバックを受けて記法を簡素化するアップデートが既に入っているので、細部は公式ドキュメントを正としてほしい。
「それ、Svelteと何が違うの?」
Hacker Newsのスレッドで一番強かった批判はこれだ。「track を $state に、@ を $ に置き換えたらSvelte 5では?」——Svelte 5のrunesを主導した本人が作っているのだから、似るのは当然ではある。
差分があるとすれば、.svelte のようなテンプレート言語を作らず、TypeScriptの拡張としてやり切ろうとしていることだ。型推論・IDE支援・エコシステムをTypeScriptのまま使う。Svelteが「HTMLの拡張」から出発したのに対し、Rippleは「TypeScriptの拡張」から出発している。この出発点の違いが最終的にどれだけ効くかが、このプロジェクトの賭けだと思う。
触っていいのか
正直に書くと、本番はまだ無理だ。作者自身が実験的フレームワークと位置づけていて、バグもTODOも大量に残っている。ロードマップも公開されていない。スターは7.4kまで来ているが、これは期待値の数字であって実績の数字ではない。
それでも眺める価値があるのは、Hooks・runes・signalsという10年分の試行錯誤を全部知っている人の「最終回答の下書き」だからだ。InfernoがReactの、SvelteがコンパイラファーストのUIの先行実験だったように、Rippleの実験が次の何かに流れ込む可能性は十分ある。
フレームワークは乗り換えるものじゃなくて、思想を輸入するもの。そう割り切って読むと、α版でも収穫は多いですよ。