⚔️ Railsぱパフォーマンス対決:Hotwireを使った最新 MPA vs React SPA

⚔️ Railsぱパフォーマンス対決:Hotwireを使った最新 MPA vs React SPA

· · 5分で読めます

Advertisement

🧭 「Rails MPA は遅い」という前提は、本当に正しいのか

Web アーキテクチャの議論では、いつの間にか次の前提が常識のように扱われています。

MPA は遅い
SPA は軽くて速い
大規模になったら SPA に移行すべき

私はこの前提を、実運用と実測値の両面から何度も検証してきました。
そして今は、かなり明確な結論を持っています。

**少なくとも EC を含む多くのプロダクトでは、
Rails + Hotwire MPA は「遅いどころか、最初に選ぶべき構成」**です。


🧭 単純な Rails モノリスで学んだこと

Rails を使い始めた頃、私は特別な設計をしていませんでした。

この構成で、最大 6 つの Rails サイトを同時に運用し、
そのうち 1 つは 60 万ユーザー規模まで成長しました。

イベント時にはアクセスが急増し、サーバー負荷は確かに上がります。
それでも私は AWS のメトリクスを眺めているだけで、サイトが壊れることはありませんでした

この経験から学んだことは、今も変わりません。

高度なリアルタイム性が必須でない限り、
モノリス + SSR は「遅い」のではなく、最も安定した構成である


🧨 EC スケールが Web アーキテクチャの前提を壊す

しかし、EC では話が変わります。

現在私は、数百万ユーザー規模の EC サイトを運用しています。
このスケールに到達すると、Web アーキテクチャの前提が一気に変わります。

問題は、この条件を 従来型の MPA でどう扱うかでした。


🧩 キャッシュという、EC 最大のジレンマ

EC では必ず次の矛盾に直面します。

要素キャッシュ
商品名・画像・説明可能
価格・在庫不可

すべてを 1 HTML に含めると、ページ全体がキャッシュ不能になります。

結果として何が起きるか。


❌ なぜ「クラシックな MPA」は破綻するのか

重要なのは、Rails が悪いのではないという点です。
問題は「同期ポーリング」という設計です。

def stock_check
  product = Product.find(params[:id])
  render json: { stock_count: product.inventory_count }
end

コード自体に問題はありません。
しかし、負荷モデルが完全に破綻しています。

📉 フラッシュセール時の現実

RPS = 10,000 ÷ 2 = 5,000 req/sec

在庫確認だけで 毎秒 5,000 リクエスト
HTML レンダリング以前に、DB の Read だけでシステムが窒息します。


🤔 「だから SPA にすべきでは?」という発想

ここで多くのエンジニアはこう考えます。

この判断は、論理的には正しい
実際、多くのチームが React SPA への移行を選びます。

しかし、ここで失われるものがあります。

🚀 SPA は何を解決し、何を失うのか

SPA は「操作中の体験」を改善します。
しかし、EC において最も重要な指標を犠牲にします。


📊 実測パフォーマンス比較(実運用)

前提条件

初期ロード性能

指標Rails + HotwireReact SPA
JS サイズ(gzip)約 42 KB約 620 KB
JS パース時間約 50 ms約 800 ms
FCP約 0.8 s約 1.8 s
TTI約 0.9 s約 3.5 s

JavaScript のコストは ダウンロードだけではありません
圧縮された 600KB の JS を、低〜中性能 CPU が解析・実行する間、
画面は 1 秒以上フリーズします。


📉 Core Web Vitals 実測(Google データ)

Google は Core Web Vitals を基準にウェブサイトを評価・ランキングしています。
以下は、p75/p95 の指標において、2 つのアーキテクチャ間で差が見られるポイントです。

指標Rails / HotwireReact SPA
LCP🟢 0.8s – 1.5s🔴 2.5s – 4.0s
TBT🟢 < 100ms🟡 300ms+
CLS🟢 0.01🟡 0.1 – 0.25

特に TBT は、Hydration がメインスレッドを占有することが原因です。


⚡ 操作応答性(INP)の真実

ただし Turbo Drive の プレビューキャッシュにより、
体感速度は SPA にかなり近づきます。


🧠 SPA が抱える構造的な負債

1️⃣ メモリリークと長時間利用問題

SPA はページ遷移してもブラウザがリセットされません。

Hotwire はページ遷移ごとに <body> が再生成されるため、
この問題が起きにくい構造です。

続きを読む


2️⃣ SEO とレンダリングキュー

Google は JavaScript を実行できますが、
HTML に比べ 数倍のクロールコストがかかります。

結果として:

SSR を導入すると、今度は Node.js 運用コストが増え、
Rails の単純さが失われます。

サンドイッチ構造

ブラウザ <--> [ 🟢 Node.js (Next.js) ] <--> [ 💎 Rails (API) ] <--> DB

続きを読む


3️⃣ ロジックの二重管理

ズレた瞬間に、

「画面では OK なのに保存できない」

Rails + Hotwire では、Model に集約できます。

続きを読む


🧪 ケーススタディ

両者は思想が真逆です。
GitHub は「初期表示」を、Twitter は「操作感」を最優先しています。


🧮 私の技術選定基準

https://digi-archive.com/uploads/d/7400f04b-1e6f-4b54-91ec-521a3587894e/3826a35a-8a7b-42d4-8dd1-fd8a40df3469/pc-79f072a7400aeb689cfd70d92437730e.webp

条件Rails + HotwireSPA
最重要指標SEO / 初期表示操作感
チーム規模小〜中
ロジック複雑単純

🏁 結論

Rails + Hotwire は、

まず選ぶべきは Rails MPA です。


❓ 最後に残る問い

私たちはこう思いがちです。

SPA は軽い。JSON だけをやり取りすればいい

しかし実際には:

100KB の HTML が 200ms で表示され、
100KB の JSON が 1.2 秒かかることは、珍しくありません。

私たちは本当に「軽量な通信」をしているのか
それとも、
ブラウザが得意だった仕事を
JavaScript にやり直させているだけなのか


Advertisement
#rails#hotwire#ruby#パフォマンス#spa#mpa#アキテクチャ#react
Advertisement