「Vite + Reactでいい」とは、Reactユーザーの一部が持ち、度々表明される意見です。
比較対象はNext.jsやその他Reactフレームワークであり、そのようなフレームワークよりも「Vite + React」というシンプルな構成を好む意見です。
現実とは、筆者が「Vite + React」を維持したままRSC (React Server Components) を活用できる新たなフレームワークFUNSTACK Staticを開発し、先般1.0.0をリリースしたことです。
「Vite + React」の特徴
Vite + Reactは、Reactを単なるフロントエンドのライブラリとして使い、ビルドツールとしてViteを直接使うスタックです。
最大の特徴は、CSR (Client Side Rendering) のSPAであることです。つまり、ビルド成果物がHTML, CSS, JSなどのアセットであり、それを静的ファイルサーバーにデプロイすれば動作します。
言い換えると、サーバーにNode.jsとかをデプロイして動かしたり、Vercelを使ったりする必要がないということです。
また、フレームワークを使わないゆえに、規約がなく、自由度が高いこともVite + Reactの特徴となります。つまり、どのようなコードが動作するのかは完全に自分達に委ねられており、フレームワークが裏で何かしているようなことはありません。
規約というのは、例えばファイルシステムベースルーティングです。つまり、フレームワークのルールに従ってファイル名やディレクトリ名を決めて配置すれば、自動的にそれに合わせたURLでページが見られるようになります。Vite + Reactではそれも自分達でやることになるので、SPA用のルーターライブラリなどを導入することになります。
「Vite + React」と他フレームワークのギャップ
「Vite + Reactでいい」という考えの背景の一つとして、他のReactフレームワークとのギャップが大きいことがあるでしょう。以前の記事でも触れたように、フレームワークはいろいろな使い方ができますが、典型的には以下のようなギャップがあります。
| Vite + React | フレームワーク | |
|---|---|---|
| サーバー | 不要 | 必要 |
| SSR | なし | あり |
RSC ("use client") |
なし | あり |
| 規約・独自機能 | なし | あり |
つまり、サーバー(ここではNode.jsなどJavaScriptが実行できるサーバーを指します)が必要な点や、最近のフレームワークはRSC (React Server Components) を基礎としており従来のやり方が通用しない点、フレームワーク独自の規約や機能(Next.jsのさまざまなキャッシュ機構が典型的ですね)を理解する必要がある点など、さまざまな違いがあります。
フレームワークでは古き良き「Vite + React」の考え方が通用しない点が多いため、フレームワークを敬遠する人が一定数存在したと考えられます。
特にこの中でも、「サーバーのある無し」は無視できない違いです。RSCとか、フレームワークの規約はどちらかというと“学習コスト”とか“ロックイン”の問題であり、筆者としてはそこまで大きな問題だと思っていないのですが、サーバーを立てなくてもいいなら立てないに越したことはありません。
そのため、わざわざサーバーを立てたくない場面に適したスタックとして「Vite + React」が推されることになり、そのついでにSSRやRSCが棄却されるという構図があります。
FUNSTACK Staticの登場
ここで筆者が開発したFUNSTACK Staticに話が移ります。より細かい紹介は以下の記事も参照してください。
要点は、FUNSTACK Staticはフレームワークだが「Vite + React」を堅持しており、サーバーは不要で、しかしRSCを取り入れていることです。これにより、従来の「Vite + React」と他フレームワークの中間の立ち位置となります。
| Vite + React | FUNSTACK Static | 他フレームワーク | |
|---|---|---|---|
| サーバー | 不要 | 不要 | 必要 |
| SSR | なし | あり(オプトイン) | あり |
RSC ("use client") |
なし | あり | あり |
| 規約・独自機能 | なし | (ほぼ)なし | あり |
また、FUNSTACK Staticは一応フレームワークを名乗っていますが、実態はViteプラグインであるため、独自のコマンド (CLI) を持ちません。以下のようなコマンドを使って開発します。
vite dev # 開発サーバー起動
vite build # ビルド
これはもうVite + Reactと言ってもいいですね。サーバー無しなので、ビルドの出力はもちろんHTML, JSなどの静的ファイルです。
また、規約・独自機能は「(ほぼ)なし」です。まず、規約は「2つのファイルを用意し、それぞれがコンポーネントをdefault exportすること」だけです。ちなみに2つのファイル名はカスタマイズ可能です。
// root.tsx
export default function Root({ children }) {
return (
<html>
...
<body>{children}</body>
</html>
);
}
// app.tsx
export default function App() {
return (
<div>My App!</div>
);
}
独自機能は、今のところdefer関数というのが提供されており、それだけです。
import { defer } from "@funstack/static/server";
root.tsx はVite + Reactでいうindex.htmlをJSXで書くようにしただけのもので、app.tsxはアプリケーションのエントリーポイントです。Vite + Reactから特に何も複雑化していませんね。deferについてはバンドルサイズ最適化(のようなこと)のために必要な機能です。
RSCの活用
FUNSTACK Staticの際立った特徴はRSCベースであることで、ここが「Vite + React」との大きな違いです。
つまり、"use client"をどこに付けるとか、クライアントからサーバーをimportしてはいけないとか、そういったルールが適用されます。
FUNSTACK Staticを使いこなすためにはRSCを使いこなせる必要があり、ここは従来の「Vite + React」とはギャップがあります。
では、なぜRSCベースなのでしょうか。それは、RSCがSPAのパフォーマンス改善に使えるからです。以前の記事で説明したので細かい説明は省きますが、サーバーが無くてもRSCをある程度活用することはできるのです。
また、「Vite + React」と比べると、サーバーコンポーネントにおいてファイル読み込みなどができることが利点となります。これにより、従来ビルド時のスクリプトやViteプラグインを使って実現しなければいけなかったことが、単なるJavaScript/TypeScriptのコードというよりシンプルな形で実現できる可能性もあります。
FUNSTACK Staticのテーマは、このようなRSCの利点を「サーバーの無いSPA」に持ち込むことなのです。
突きつけられた現実
記事タイトルにある「突きつけられた現実」とは、言うまでもなくFUNSTACK Staticが登場したことです。
「Vite + Reactでいい」と言う人は、それをどういう意味で言っているのか、再考する必要が出てきます。
先ほどの表を再掲しますが、従来の「Vite + React」と「他のフレームワーク」には大きなギャップがあったので、「Vite + Reactでいい」は多くの含意と可能性を含んでいました。サーバーがあるのが嫌なのか? RSCが嫌なのか? フレームワークにファイル名を縛られるのが嫌なのか? などです。
| Vite + React | FUNSTACK Static | 他フレームワーク | |
|---|---|---|---|
| サーバー | 不要 | 不要 | 必要 |
| SSR | なし | あり(オプトイン) | あり |
RSC ("use client") |
なし | あり | あり |
| 規約・独自機能 | なし | (ほぼ)なし | あり |
FUNSTACK Staticが、両者の中間の位置に出現しました。FUNSTACK Staticは、Viteのコマンドをそのまま使えるし、サーバー不要で静的ファイルサーバーにアプリをホスティングできるし、ファイル名のルールもありません。RSCはあります。
「Vite + Reactでいい」人は、FUNSTACK Staticならいいのか? それもだめなのか? を考えなければなりません。そのために、自分はどうして「Vite + Reactでいい」のか、解像度を上げる必要があります。
特に、「サーバーの有無」という大きな違いがこれまで「Vite + Reactでいい」に説得力を持たせてきたように思います。もちろん用途次第でサーバーがあったほうがいいReactアプリもありますが、別にサーバーが無くてもいいアプリもあるでしょう。サーバーのある無しは、インフラ等も関わるサービス設計の問題なのです。
そこが同じになれば、他の論点(RSCを使うかどうかなど)はソースコードレベルの問題になります。学習コスト、メンテナンス性、(ソースコードの)アーキテクチャといったことです。
ぶっちゃけると、筆者はRSCが過度に忌避される傾向にあると思っており、その隠れ蓑として使われがちな「サーバーの有無」という違いを排除したかったのです。
2つの選択肢
2つの選択肢とは、もちろん、FUNSTACK Staticを「Vite + Reactでいい」の仲間に入れるのか入れないのかということです。
FUNSTACK Staticはツールの使い方とその出力結果だけ見れば「Vite + React」の範疇に入ることは明らかです。しかし、従来の「Vite + React」と大きく異なり、RSCを採用しています。
もし、あなたの本心が「RSCが嫌だ」であれば、これからは「Vite + Reactでいい」ではなく「RSCを使いたくない」というほうが理にかなっています。
もし、あなたが「サーバー不要のSPAが出力できるならRSCを使う」のであれば、「Vite + Reactでいい」は依然正しいです。
もちろん、筆者としては後者をお勧めします。パフォーマンスの改善、特にクライアントの負荷軽減はSPA開発における重要な要素であり、RSCはそれに貢献してくれるからです。
まとめ
この記事では筆者が開発したFUNSTACK Staticを宣伝し、「Vite + Reactでいい」という意見が2つに分裂しうることを指摘しました。
余談ですが、FUNSTACK Staticの開発を始めたのは今年1月です。昔に比べて余暇に使える時間が相当減っている中でもOSS開発ができるのはAI様々ですね。ただ、さすがにRSC対応のReactフレームワークを1から作ることは現在のAIに難しく、一番コアの部分は温かみのある手書きで書かれました。
といっても、本当のコア部分は@vitejs/plugin-rscです。これを開発してくださった方々には足を向けて寝られません。