フロントエンドでフレームワークが毎年変わる理由

フロントエンドのフレームワークが「毎年変わる」と感じる理由

フロントエンドは不安定な分野だから毎年技術が変わっている、と思われがちですが、実際にはそうではありません。
変わっているのは「流行」ではなく解決しようとしている問題の場所です。問題の場所が移動するたびに、最適なフレームワークが変わっているだけです。

つまり、フロントエンドは場当たり的に新しいものが出ているのではなく、
「ボトルネックが移動 → 最適解が変化 → フレームワークが交代」
という構造で進化しています。

この構造を知らないと、Reactの次は何か、なぜ新しいものが出続けるのかが理解できません。

そもそもフロントエンドの役割が変わり続けている

昔のWebページは、単なる文書でした。
サーバがHTMLを作り、ブラウザはそれを表示するだけです。

時代 フロントエンドの役割
2000年前後 HTML表示(文書ビューア)
2010年前後 UI操作(アプリ的挙動)
2020年前後 状態管理・画面遷移
現在 アプリケーション実行環境

この役割の変化が、フレームワーク交代の本質です。

昔のフロントエンドでは、JavaScriptは補助機能でした。
しかし現在は、アプリケーションの本体がブラウザで動いています。

役割が変われば、必要な設計思想も変わります。
その結果、フレームワークが入れ替わります。

jQueryが最適だった時代

最初の問題は「ブラウザが動かない」でした。

Internet Explorer、Firefox、SafariでDOMの仕様が違い、同じJavaScriptが動きません。
その差異を吸収したのがjQueryです。

jQueryの役割はUIライブラリではありません。
ブラウザ互換レイヤーです。

例えばクリックイベントです。

document.getElementById("btn").onclick = function(){};

昔はこれがブラウザごとに挙動が違いました。
jQueryはそれを統一しました。

$("#btn").on("click", function(){});

つまり当時のボトルネックは「ブラウザ差異」であり、
それを解決する最適解がjQueryでした。

次の問題:画面が壊れる

AJAXが普及すると、ページ遷移せず画面を書き換えるようになります。
ここで新しい問題が発生します。

DOMが複雑になり、管理不能になる

例として、次のような状態になります。

  • ボタンを押すとリストが増える
  • 削除すると別のUIが更新される
  • 並び替えるとカウンターが変わる

jQueryは「操作」は得意ですが、「状態」は扱えません。
どこを変更すれば正しい画面になるのかが人間にしか分からなくなります。

この問題の名前が「状態管理」です。

SPAフレームワークが登場した理由

React、Vue、Angularが解決したのはUIではありません。
状態管理です。

Reactの本質はVirtual DOMではなく、

「状態が変わればUIが決まる」

という一方向データフローです。

つまり

jQuery
→ DOMを直接操作する

React
→ 状態を変更するだけでDOMが決まる

この違いにより、画面崩壊が防げるようになりました。

フレームワークが変わったのではなく、
ボトルネックが「ブラウザ差異」から「状態管理」に移動したのです。

さらに新しい問題:表示が遅い

SPAが普及すると、新たな問題が発生します。

初回表示が遅い

理由は単純で、ブラウザがアプリをダウンロードしてから描画するためです。

SPAの初回表示の流れはこうなります。

1. HTML取得
2. JSダウンロード
3. JS実行
4. DOM生成
5. 画面表示

つまり、ページ表示前にアプリが起動しています。
これがSEOとLCPの問題を引き起こしました。

ここで登場したのがSSRです。

SSRが流行した本当の理由

SSRはSEO対策のため、と思われがちですが半分違います。
本当の目的は描画の場所をサーバに戻すことです。

SPAは「クライアントCPU」がボトルネックでした。
SSRはそれを「サーバCPU」に移した技術です。

方式 描画する場所
SPA ブラウザ
SSR サーバ

これにより初回表示が劇的に速くなりました。

つまりフレームワークの変化ではなく、
計算資源の配置変更が起きています。

そして現在:RSCが出てきた理由

SSRでも問題は残りました。

それは「不要なJavaScriptが多すぎる」ことです。

ユーザーが触らない部分までJSが配布され、
モバイル端末でパフォーマンスが悪化しました。

React Server Components(RSC)はここを解決します。

  • インタラクションが必要な部分だけJS配布
  • それ以外はサーバ描画

つまりRSCはSSRの次ではなく、
JS配布量の最適化です。

フレームワークが毎年変わるように見える本当の原因

ここまでを見ると、共通点があります。

時代 ボトルネック 登場技術
ブラウザ差異 互換性 jQuery
状態管理 UI破壊 React/Vue
初回表示 CPU負荷 SSR
JS配布量 通信量 RSC

フレームワークは毎年変わっているのではありません。
解決対象の問題が移動しているだけです。

よくある誤解と注意点

ここでよくある失敗があります。

「新しいフレームワーク=優れている」

これは正確ではありません。
新しいものは「新しい問題」に強いだけです。

例えば、社内管理ツールにRSCを導入しても効果は薄い可能性があります。
ネットワーク遅延やSEOが問題でない場合、SSRのメリットが小さいためです。

つまり技術選定は流行ではなく、
どのボトルネックを解決したいかで決める必要があります。

最後に

フロントエンドが落ち着かない分野に見えるのは、技術が不安定だからではありません。
むしろ逆で、Webが本格的なアプリ実行環境へ変化している途中だからです。

jQueryもReactもSSRもRSCも、別々の技術ではありません。
全部「同じ問題の延長線」にあります。

新しいフレームワークを追い続けるよりも、
「何を解決するための技術なのか」を理解した方が、結果的に長く使える知識になります。

流行を追うより、ボトルネックを見てください。
フロントエンドはその瞬間の最適解が名前を変えているだけです。

SPAでメタタグ管理が難しくなる理由

SPAでは「head」がページごとに存在しない

SPAでメタタグ管理が難しい理由は単純です。
SPAは本来ページ単位で存在するはずの<head>を、アプリケーション起動時に1回しか読み込まないからです。

通常のWebページでは、URLごとに別のHTMLが返ります。
つまりページが変われば<title>やdescriptionも自動的に変わります。

しかしSPAではURLが変わってもページ遷移は発生しません。
ここがSEOやSNSシェアで問題を生む根本原因です。

通常のWebページでメタタグが機能する仕組み

通常のMPAでは次のようなHTMLが返ります。

<head>
  <title>商品A</title>
  <meta name="description" content="商品Aの説明">
</head>

別のURLへ移動すると、新しいHTMLが届きます。

<head>
  <title>商品B</title>
  <meta name="description" content="商品Bの説明">
</head>

ブラウザは新しい文書として扱います。
検索エンジンもこのheadを解析します。

つまりメタタグは「文書の属性」です。
本来アプリケーションの状態ではありません。

SPAではHTMLが1回しか来ない

SPAの初期レスポンスは次の形になります。

<head>
  <title>My App</title>
</head>
<body>
  <div id="app"></div>
  <script src="/app.js"></script>
</body>

その後、ユーザーが商品ページを開いても新しいHTMLは届きません。
JavaScriptがDOMを書き換えるだけです。

つまり検索エンジンやSNSクローラが受け取るheadは最初の1回だけになります。

なぜこれが問題になるのか

SEOとSNSプレビューは、次の情報をheadから取得します。

  • title
  • description
  • og:image
  • og:title

例えばSNS共有では、URLの情報を取得してカードを生成します。
SPAでメタタグを書き換えても、クローラがJavaScriptを実行しない場合、最初のtitleのままになります。

結果として次の現象が起きます。

  • すべてのページが同じタイトル
  • 商品ページなのにトップの説明文
  • SNSカードが壊れる

headを書き換えれば良いのでは?

もちろんJavaScriptで変更は可能です。

document.title = "商品A";

しかし問題は「誰が読むか」です。
ユーザーのブラウザは反映されますが、クローラは反映されない場合があります。

特にSNSクローラはJavaScriptをほとんど実行しません。
サーバから受信したHTMLのみを解析します。

head管理ライブラリが必要になる理由

そこで登場するのがhead管理ライブラリです。

役割は単なるtitle変更ではありません。
ルーティング状態とメタ情報を同期させることです。

例:ルートに応じてheadを変更

route("/product/:id", id => {
  setMeta({
    title: "商品" + id,
    description: "商品詳細"
  });
});

これによりユーザー体験は改善します。
ただしSEOはまだ解決していません。

なぜSSRがこの問題を解決するのか

SSRではURLごとにHTMLを生成します。

<head>
  <title>商品A</title>
  <meta name="description" content="商品Aの説明">
</head>

クローラはJavaScriptを実行せずに情報を取得できます。
これが「SPAはSEOに弱い」と言われる理由の一部です。

Prerenderという回避策

SPAでも対策はあります。
Prerender(事前レンダリング)です。

ビルド時にページごとのHTMLを生成します。

  • /product/1.html
  • /product/2.html

クローラにはこの静的HTMLを返し、ユーザーにはSPAを返します。
これによりメタタグ問題を回避できます。

実務で起きやすい落とし穴

最も多いのは次の誤解です。

「ブラウザでタイトルが変わっているからSEOも大丈夫」

これは危険です。
確認しているのは人間のブラウザであり、検索エンジンの挙動ではありません。

特にOGP画像が出ない問題は、ほぼメタタグ取得タイミングが原因です。

どう理解するとよいか

SPAは「アプリケーション」です。
一方メタタグは「文書の属性」です。

アプリケーションの状態変化と文書の属性は本来別物です。
SPAは文書を1回しか配布しないため、文書属性の更新と相性が悪くなります。

そのためhead管理ライブラリが必要になり、さらにSEOを考えるとSSRやPrerenderが検討対象になります。

メタタグ問題はSEOテクニックの話ではありません。
「ページ」という概念を持つWebと、「画面」という概念を持つSPAの設計差から自然に発生する現象です。

SSRはなぜアクセシビリティに有利と言われるか

SSRは「アクセシビリティを実装しやすい」構造を持っている

SSRでアクセシビリティ(a11y)が有利になると言われるのは、SSRの方が丁寧に作られているからではありません。
ブラウザや支援技術が理解できる形のHTMLが最初から存在するためです。

アクセシビリティは「親切に作ること」ではなく、「機械が理解できる構造を提供すること」です。
スクリーンリーダー、キーボード操作、検索エンジンはすべてHTMLを解析して動作します。

このとき重要になるのが「最初に届くHTML」です。

スクリーンリーダーはJavaScriptを待たない

多くの支援技術はページを読み上げる際、まず受信したHTMLを解析します。
ここで内容が存在しなければ、何も読み上げられません。

SPAの初期レスポンスは次のようになります。

<div id="app"></div>

この時点では本文がありません。
JavaScriptが実行されるまで、スクリーンリーダーは内容を取得できません。

通信が遅い環境、CPU性能が低い端末、JavaScript制限環境では「空ページ」と認識されることがあります。

SSRでは意味構造を直接伝えられる

SSRでは最初のレスポンスに意味のあるHTMLが含まれます。

<main>
  <h1>お知らせ</h1>
  <article>
    <h2>メンテナンス情報</h2>
    <p>本日…</p>
  </article>
</main>

スクリーンリーダーは到着直後に構造を把握できます。

  • 見出しジャンプ
  • ランドマーク移動
  • 読み上げ順序

これらが正常に機能します。
これがSSRがアクセシビリティで有利になる最大の理由です。

キーボード操作との関係

アクセシビリティで重要なのはマウスを使わない操作です。
キーボード利用者は次の操作を多用します。

  • Tab移動
  • 見出し移動
  • フォーカス移動

SPAではJavaScriptがフォーカスを管理します。
画面更新時にフォーカス位置が失われる問題が起きやすくなります。

例:ルーター遷移

router.push("/about");

見た目はページ遷移ですが、実際はDOMの一部差し替えです。
ブラウザは「新しいページが表示された」と認識しません。
結果としてフォーカスが不適切な位置に残ります。

SSRではページロードが発生するため、フォーカスは自然に先頭へ移動します。

ARIAの役割が変わる

SPAではしばしば次の属性が必要になります。

  • aria-live
  • role="alert"
  • aria-busy

これは「画面が更新された」ことを支援技術に知らせるためです。
SPAはページ遷移が起きないため、状態変化を手動で通知する必要があります。

SSRではページロード自体が通知になります。
結果としてARIA依存が減ります。

実務で起きる典型的な問題

SPAでアクセシビリティ対応をすると、次の問題に直面します。

  • 読み上げが途中で止まる
  • 更新内容が伝わらない
  • 戻る操作で位置が分からない
  • モーダルが閉じられない

これらはUI設計の問題ではなく、「ページ遷移が存在しない」ことによる影響です。

SEOとの関係

検索エンジンもHTMLを解析します。
最近のクローラはJavaScriptを実行しますが、完全ではありません。

SSRでは

  • 見出し構造
  • 本文
  • リンク関係

が最初から取得できます。
アクセシビリティ対応とSEO対応が同時に改善する理由はここにあります。

ただしSSRなら自動でa11yが良くなるわけではない

重要な点として、SSRはアクセシビリティを保証しません。
間違ったHTMLを返せば当然問題は起きます。

例:

<div onclick="go()">ボタン</div>

これはSSRでもアクセシブルではありません。
ボタン要素を使う必要があります。

つまりSSRは「有利」ですが「自動対応」ではありません。

どう理解すればいいか

アクセシビリティはJavaScriptの問題ではなく、文書構造の問題です。
SSRは文書を先に提供し、SPAはアプリケーションを先に起動します。

支援技術が理解するのは文書です。
そのためSSRの方が自然に適合します。

SSRはアクセシビリティのための技術ではありません。
しかし、HTML中心のWeb本来の動作モデルに近いため、結果としてa11y対応を実装しやすくなります。

アクセシビリティ対応で苦労したとき、コード量ではなく「最初のHTMLに意味があるか」を確認することが、最も効果的な改善になることが多いです。

SPAでフォーム送信が難しくなる本当の理由

SPAは「submit」を止めることで成立している

SPAでフォーム送信が難しくなる理由は、ReactやVueが難しいからではありません。
SPAというアーキテクチャ自体が、ブラウザ本来のフォーム送信機能を無効化して動いているからです。

つまり、SPAはフォームを「拡張」しているのではなく、いったん破壊してからJavaScriptで再実装しています。
ここを理解すると、なぜバリデーション・リダイレクト・戻るボタンなどで問題が起きるのかがはっきり見えてきます。

ブラウザのネイティブsubmitはとても高機能

まず通常のHTMLフォームの動作を整理します。

<form action="/users" method="POST">
  <input name="name">
  <button type="submit">送信</button>
</form>

ボタンを押すと、ブラウザは次の処理を自動で行います。

  • 入力値収集
  • バリデーション
  • リクエスト生成
  • ページ遷移
  • 履歴追加

JavaScriptは不要です。
さらに、Enterキー送信、フォーカス移動、オートコンプリート、アクセシビリティ支援まで含まれます。

つまりHTMLフォームは、単なるUI部品ではなくブラウザ組み込みのアプリケーション機能です。

SPAはsubmitをキャンセルしている

SPAではページ遷移を起こしてはいけません。
なぜならSPAは「単一ページ」を維持するアプリケーションだからです。

そのため、フレームワークはsubmitイベントを止めます。

form.addEventListener("submit", e => {
  e.preventDefault();
});

これがすべての始まりです。
この瞬間、ブラウザが持っていたフォーム機能は動作しなくなります。

代わりに何が起きているのか

SPAでは、送信処理をJavaScriptで書き直します。

async function onSubmit() {
  const name = input.value;
  await fetch("/api/users", {
    method: "POST",
    body: JSON.stringify({ name })
  });
}

見た目は同じ「送信ボタン」ですが、中身はまったく別の仕組みです。
ブラウザではなくアプリケーションコードが通信を担当します。

この変更により、多くの副作用が発生します。

なぜ問題が頻発するのか

ネイティブsubmitが消えると、次の機能をすべて自分で実装する必要があります。

  • 必須チェック
  • エラーメッセージ
  • 2重送信防止
  • リダイレクト
  • 履歴管理
  • 戻るボタン対応

例えばEnterキー。
通常は自動送信されますが、SPAでは反応しないことがあります。
キーボードイベントを個別に処理していないためです。

また、ブラウザのバリデーションも無効になります。

<input required>

ネイティブでは未入力時に送信できません。
しかしSPAではfetchが実行され、サーバに空データが送られることがあります。

特に壊れやすい「リダイレクト」

通常のフォーム送信では、サーバは次のレスポンスを返します。

HTTP/1.1 302 Found
Location: /complete

ブラウザが自動で遷移します。
しかしSPAではfetchがレスポンスを受け取るだけで、画面は変わりません。

そのため、次の処理を追加する必要があります。

router.push("/complete");

このとき履歴が正しく積まれないと、戻るボタンで再送信が起きるなどの問題が発生します。

なぜSSRでは問題が少ないのか

SSRではフォーム送信後にページ遷移が起きます。
つまりブラウザの標準挙動をそのまま使えます。

  • POST
  • リダイレクト
  • 新ページ表示

この一連の流れは数十年ブラウザで最適化されています。
SPAはそれをJavaScriptで再現しようとしているため、複雑になります。

よくある失敗例

実務で頻繁に起きる問題です。

  • 送信ボタン連打で多重登録
  • 戻るで再送信警告が出ない
  • オートフィルが効かない
  • IME確定前に送信される

これらはフレームワークのバグではありません。
ネイティブフォームを置き換えた副作用です。

SPAでフォームを扱うときの注意点

重要なのは「フォームを普通のUIだと思わない」ことです。

フォームは単なる入力欄ではなく、
ブラウザの通信機構と履歴機構を内包した機能です。

SPAではそれを再実装していると意識すると、設計が安定します。

どう考えると楽になるか

SPAでフォームが難しいのは、フレームワークの習熟不足ではありません。
アーキテクチャ上の必然です。

SPAはページ遷移を消し、代わりにJavaScriptで状態遷移を管理します。
フォーム送信は本来「ページ遷移を伴う通信」です。
この2つは思想が衝突します。

だから多くのモダンフレームワークは最近、ネイティブsubmitへ回帰する仕組み(Server Actionsなど)を導入し始めています。

フォームで悩んだときは、
「なぜこんなに面倒なのか」ではなく
「ブラウザが本来やっていた仕事を自分が背負っている」と考えると、設計の方向が見えやすくなります。

SSRでもREST APIが有利になる技術的な場面

SSRではGraphQLよりREST APIが自然に機能する場面がある

最近は「SPA=GraphQL」「モダン=GraphQL」という印象が強くなっていますが、SSRでは事情が少し変わります。
SSRでは依然としてREST APIの方が扱いやすく、性能面でも有利になるケースが少なくありません。

これは好みや宗教ではなく、レンダリング方式の違いによるものです。

SSRは「ページ単位」でデータを集めます。
一方GraphQLは「コンポーネント単位」でデータを要求する思想です。
この前提の差が挙動を変えます。

SSRは“ページ生成処理”である

SSRの処理は次の順序になります。

  • HTTPリクエスト受信
  • 必要データを取得
  • HTMLを生成
  • レスポンス返却

つまりSSRでは、レンダリング前に必要な情報がすべて揃っていることが前提になります。

ここで重要なポイントがあります。
SSRでは「画面部品が個別に通信する」ことがありません。

SPAではコンポーネントごとにAPIを呼びますが、SSRではサーバが一括取得します。
この時、REST APIの構造が非常に噛み合います。

REST APIは「まとめて取得」に強い

例えば記事ページを表示するケースを考えます。

必要なデータ:

  • 記事本文
  • 著者
  • コメント一覧
  • 関連記事

RESTなら以下のように取得できます。

GET /articles/10
GET /articles/10/comments
GET /articles/10/related

SSRではこれらをサーバ内部で並列取得し、HTMLに埋め込みます。
ブラウザは1回のレスポンスで完成ページを受け取ります。

GraphQLの場合、1クエリで同じことは可能です。

query {
  article(id:10){
    title
    body
    author { name }
    comments { body }
    related { title }
  }
}

一見GraphQLが優れているように見えます。
しかしSSRでは別の問題が出ます。

SSRとGraphQLで発生しやすいボトルネック

GraphQLの処理は次の流れになります。

  • クエリ解析
  • リゾルバ呼び出し
  • データ解決
  • 結果統合

この「リゾルバ」がSSRと相性の難しい部分です。
コンポーネントごとにデータ解決が発生するため、内部的に多数のDBアクセスが生まれます。

典型例がN+1問題です。

記事1件 → コメント10件 → 投稿者10人

RESTでは1クエリで取得していた情報が、GraphQLでは複数回の問い合わせになる場合があります。
SSRではリクエストごとにこれが発生するため、CPUとDB負荷が増えやすくなります。

キャッシュ戦略が大きく違う

SSRではキャッシュが非常に重要です。
特にCDNキャッシュが効くかどうかが性能を左右します。

REST APIはURL単位でキャッシュできます。

URL キャッシュ
/articles/10 可能
/articles/10/comments 可能

一方GraphQLは通常POSTリクエストです。

POST /graphql

クエリ内容が毎回異なるため、CDNキャッシュが効きません。
結果として毎回アプリケーションサーバまで到達します。

SSRではこの差が大きくなります。
HTMLキャッシュとAPIキャッシュを組み合わせると、RESTの方が構成を単純にできます。

セキュリティ面の違い

REST APIはエンドポイント単位で権限管理できます。

  • /admin/*
  • /public/*

SSRではサーバがAPIを呼ぶため、アクセス制御をサーバ側に集約できます。
GraphQLは単一エンドポイントのため、フィールドレベル認可が必要になります。
実装を誤ると情報漏洩のリスクが増えます。

実務でよく起きる現象

SPAからSSRへ移行するプロジェクトでよく見られるのが、GraphQLサーバの負荷急増です。

理由は単純です。
SPAでは「ユーザー操作時のみ」だったデータ取得が、SSRでは「アクセスのたび」に発生するためです。

つまりSSRは、バックエンドの呼び出し頻度を増やします。
GraphQLの柔軟性が、そのまま負荷増加に直結することがあります。

REST APIが向くSSRのケース

  • 記事サイト
  • ECの商品ページ
  • 公開コンテンツ
  • キャッシュ主体のサービス

これらはページ単位のデータが固定的です。
RESTのURLベース設計と一致します。

逆にGraphQLが向く場合

  • ダッシュボード
  • 個別最適化UI
  • クライアント主導画面

つまりSPA寄りのUIです。

最後に整理すると

RESTとGraphQLの違いは「古い・新しい」ではありません。

REST:リソース取得モデル
GraphQL:問い合わせモデル

SSRはページ生成処理です。
ページという「固定構造」を生成する場合、リソース単位のREST APIが自然に適合します。

GraphQLはコンポーネント駆動のクライアントアプリケーションと相性が良い設計です。
そのため、SSRではREST APIが依然として合理的な選択になる場面が残り続けます。

APIは流行ではなく、レンダリング方式に合わせて選ぶものです。
SSRを採用したとき、GraphQLが最適とは限らない理由はここにあります。

SPAとGraphQLが結びつく理由とOverfetch問題

SPAでは「必要なデータだけ欲しい」ためGraphQLが選ばれやすい

SPAでGraphQLが採用されやすい理由は、流行でも思想でもありません。
SPAのデータ取得モデルが、REST APIよりもGraphQLの方に適合しやすいからです。

そしてその背景にあるのが「Overfetch(オーバーフェッチ)問題」です。

結論から言うと、SPAは「画面の部品ごとにデータを要求するアプリケーション」です。
REST APIは「リソース単位でデータを返す設計」です。
このズレがパフォーマンスと設計の摩擦を生みます。

REST APIは“画面”ではなく“資源”を返す

REST APIはリソース志向です。
典型的なエンドポイントは次のようになります。

  • /users/1
  • /orders/15
  • /products/10

つまり「ユーザー」「注文」「商品」という単位でデータが返ります。

例えばユーザーAPI。

{
  "id": 1,
  "name": "Taro",
  "email": "taro@example.com",
  "address": "Tokyo",
  "phone": "090-xxxx",
  "created_at": "2024-01-01",
  "updated_at": "2024-01-01"
}

しかしSPAの画面では、すべての項目を使うとは限りません。
ヘッダーに表示したいのは「名前」だけ、というケースは非常に多いです。

ここでOverfetchが発生します。

Overfetch問題とは何か

Overfetchとは、必要ないデータまで取得してしまう状態です。

SPAではコンポーネントごとに必要な情報が異なります。

例:

コンポーネント 必要なデータ
ヘッダー ユーザー名
プロフィール 住所・電話
管理画面 全項目

REST APIは同じレスポンスを返すため、ヘッダー表示のためだけに巨大なJSONを受信することになります。
モバイル回線ではこの差が体感速度に直結します。

SPAは“画面中心設計”のアプリケーション

SPAではReactやVueのコンポーネントが単位になります。

<UserName id="1" />

このコンポーネントが必要なのは名前だけです。
しかしRESTではリソース全体が返ります。

つまり、

REST:サーバ中心のデータ構造
SPA:画面中心のデータ要求

この構造差がGraphQLの登場理由です。

GraphQLは「画面が欲しい形でデータを取得する」

GraphQLではクエリで必要項目を指定します。

query {
  user(id: 1) {
    name
  }
}

レスポンス:

{
  "data": {
    "user": {
      "name": "Taro"
    }
  }
}

住所も電話も送られません。
つまりOverfetchが発生しません。

これがSPAでGraphQLが採用されやすい最大の理由です。

Underfetch問題も同時に解決する

RESTでは逆の問題も起きます。
「情報が足りない」問題です。

例:ユーザーと注文履歴を同時表示したい場合

  • /users/1
  • /orders?user_id=1

2回の通信が必要になります。
これをUnderfetchと呼びます。

GraphQLなら1回のリクエストです。

query {
  user(id: 1) {
    name
    orders {
      id
      total
    }
  }
}

SPAではコンポーネントが多いため、この差が非常に大きくなります。

それでもGraphQLが万能ではない理由

GraphQLにも明確なデメリットがあります。
最大の問題はキャッシュです。

RESTはURL単位でキャッシュできます。

  • GET /users/1

一方GraphQLはPOSTで任意クエリを送ります。

POST /graphql

クエリが毎回異なるためCDNキャッシュが効きません。
トラフィックが増えるとサーバ負荷が増大します。

現場で起きる意外な問題

GraphQLを導入すると、フロントエンドがAPI設計を主導します。
その結果、バックエンドの最適化が難しくなります。

例えば次のクエリ。

query {
  users {
    orders {
      items {
        product {
          reviews {
            rating
          }
        }
      }
    }
  }
}

一見便利ですが、内部では膨大なDBアクセスが発生します。
N+1問題が起きやすくなります。

どちらを選ぶべきか

SPAだから必ずGraphQL、というわけではありません。

GraphQLが向くケース

  • 画面ごとに必要データが違う
  • モバイル通信が多い
  • UIが頻繁に変わる

RESTが向くケース

  • シンプルなCRUD
  • キャッシュ重視
  • 公開API

最後に理解しておきたいこと

GraphQLが広まったのは「新しいから」ではありません。
SPAというアーキテクチャが、RESTの前提と合わなくなった結果です。

RESTはサーバ中心設計、
SPAは画面中心設計。

GraphQLはその間を埋めるための「問い合わせ言語」です。

つまりGraphQLはRESTの代替ではなく、
SPAのデータ取得モデルに合わせたAPIの形と捉えると理解しやすくなります。

SSRがマルチテナントWebに向いている理由

マルチテナントWebではSSRのほうが自然に設計できる

SaaSなどのマルチテナントWebを設計するとき、SPAよりSSRのほうが扱いやすくなる場面が多くあります。
理由は単純で、マルチテナントは「ユーザーごとに別のWebサイトを返す」アプリケーションだからです。

同じURLにアクセスしても、ログインしている企業や契約プランによって画面構成が変わる。
これがマルチテナントの基本的な特徴です。

SSRはリクエスト単位でHTMLを生成します。
つまり「アクセスしたユーザーの情報を見て、返すページを変える」という処理が得意です。

マルチテナントの本質は“ページが人によって違う”こと

例えば管理画面型のSaaSを考えてみます。

同じURLでも次の差が発生します。

要素 変化内容
ロゴ 企業ごとに違う
メニュー 契約プランごとに違う
表示項目 権限ごとに違う
テーマカラー 企業設定ごとに違う

つまりマルチテナントとは、単なるログイン機能ではありません。
ページテンプレート自体がユーザーごとに変化するWebです。

ここでSPAとSSRの違いが出ます。

SPAで起きる問題:表示前に大量の情報が必要

SPAはまず共通HTMLを返します。

<div id="app"></div>

その後、JavaScriptがAPIを呼び出し、ユーザー情報を取得してから画面を組み立てます。

つまりSPAでは次の手順になります。

  • JSダウンロード
  • JS実行
  • 認証確認
  • テナント情報取得
  • メニュー取得
  • 画面描画

マルチテナントでは必要なデータが多いため、最初の表示が遅くなりがちです。
特に権限・ロール・設定が複雑なSaaSほど顕著です。

SSRでは「最初から完成した画面」を返せる

SSRではサーバがユーザーを識別してからHTMLを生成します。

<header style="background:#2a6df4">
  <img src="/tenantA/logo.png">
</header>
<nav>
  <li>請求書</li>
  <li>契約管理</li>
</nav>

ブラウザは受信直後に表示できます。
追加のAPI呼び出しを待つ必要がありません。

つまりSSRは、

  • テナント判定
  • 権限判定
  • UI構築

をサーバ側で完結できます。
マルチテナントと相性が良い理由はここです。

キャッシュ設計とも相性が良い

もう一つ重要な理由があります。
マルチテナントではキャッシュ戦略が難しくなります。

SPAではAPIレスポンスをキャッシュしますが、テナントごとに内容が違うため再利用しにくくなります。
一方SSRでは、HTMLをテナント単位でキャッシュできます。

例:CDNキャッシュキー

キー 意味
/tenantA/dashboard A社のダッシュボード
/tenantB/dashboard B社のダッシュボード

これによりサーバ負荷を抑えながら高速表示が可能になります。

セキュリティ面でも有利になる

SPAでは権限チェックの一部がクライアントに残ります。
APIは当然サーバで保護しますが、UI制御はJavaScriptです。

つまり、

  • ボタンを非表示にする
  • メニューを隠す

といった処理はクライアント依存になります。
実装を誤ると「見えてはいけない操作」が表示される事故が起きます。

SSRではそもそもHTMLを生成しないため、安全側に倒しやすくなります。

ただしSSRにも弱点がある

マルチテナントと相性が良いとはいえ、万能ではありません。
最も大きな問題はサーバ負荷です。

テナントごとにページを生成するため、

  • アクセス増加
  • 企業数増加
  • 機能増加

に比例してCPU負荷が増えます。
ピーク時にレスポンスが急激に悪化することがあります。

特に帳票系SaaSでは顕著です。

SPAのほうが向くケースもある

リアルタイム性が重要な場合はSPAが有利です。

  • チャット
  • コラボ編集
  • ライブ監視画面

これらは常時更新されるため、SSRで毎回レンダリングすると逆効果になります。

どう理解すればよいか

マルチテナントWebの難しさは「ログイン後に別サイトになる」点にあります。
ユーザーによってサイト構造が変わる以上、サーバがUI構築を担当するほうが自然です。

SSRはページを生成する技術というより、リクエストに応じてUIを構成するサーバアプリケーションです。

一方SPAは、共通UIにデータを流し込むクライアントアプリケーションです。

テナントごとに構造が変わるならSSR、
同じ構造でデータだけ変わるならSPA。

この視点で選ぶと、設計の迷いがかなり減るはずです。