🌊 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の実験が次の何かに流れ込む可能性は十分ある。

フレームワークは乗り換えるものじゃなくて、思想を輸入するもの。そう割り切って読むと、α版でも収穫は多いですよ。

元ネタ: https://github.com/Ripple-TS/ripple