SPA

ページ遷移なしに動的にコンテンツを更新する Web アプリケーションのアーキテクチャ

Webフロントエンド
SPA」の技術書を見る →

SPA とは

SPA (Single Page Application) は、最初に 1 つの HTML ページを読み込み、以降のページ遷移をブラウザ側の JavaScript で処理する Web アプリケーションアーキテクチャである。サーバーからは API (JSON) でデータだけを取得し、画面の描画はクライアント側で行う。Gmail や Google マップのように、画面を切り替えながら長時間使い続けるアプリの操作感は、この構成が支えている。

MPA との比較

違いは体感速度がどこで生まれるかにある。SPA は初回に重い荷物をまとめて運び、その代わり以降の遷移を軽くする。MPA は遷移ごとにサーバーと往復する。

観点SPAMPA (Multi Page Application)
ページ遷移JavaScript で画面を切り替え (高速)サーバーから新しい HTML を取得 (遅い)
初期ロード遅い (JS バンドルのダウンロード)速い (HTML だけ)
SEO描画後の HTML を読ませる工夫が必要 (SSR/SSG)初期 HTML に本文があり有利
UXネイティブアプリに近い操作感ページ遷移のたびに白画面
サーバー負荷静的ファイルの配信と API遷移ごとに HTML を返す (静的化すれば差は縮む)

SPA の動作フロー

初回表示から画面遷移までの流れは次のようになる。

1. ブラウザが index.html を取得 (ほぼ空の HTML)
2. JavaScript バンドル (main.js) をダウンロード・実行
3. React/Vue が DOM を構築し、画面を表示
4. ユーザーがリンクをクリック
5. JavaScript が history.pushState() で URL と履歴を書き換え (ページの再読み込みは起きない)
6. 対応するコンポーネントを表示 (サーバーへのリクエストなし)
7. データが必要な場合は API (fetch) でサーバーに問い合わせ

要になるのは 5 の History API だ。history.pushState() はセッション履歴にエントリを追加するだけで、ドキュメントの読み込みは行わない。だから URL だけを目的の画面に合わせ、描画は JavaScript が担う形が成り立つ。ユーザーが戻る・進むを押すと popstate イベントが発生し、そのとき渡される state オブジェクトから画面を復元する。履歴を増やしたくない更新 (絞り込み条件を URL に反映する等) には history.replaceState() を使う。落とし穴は popstate の購読漏れで、これを忘れるとブラウザバックで URL だけ変わって画面が取り残される。

S3 + CloudFront でのホスティング

SPA は静的ファイル (HTML, JS, CSS) だけで構成されるため、S3 + CloudFront でホスティングできる。サーバーが不要でコストが最小限だ。

ただし配信側に一手間が必要になる。/users/42 のような画面はクライアント側のルーティングで作られるので、その URL を直接開かれるとオリジンに該当するファイルが無く、エラーが返って画面が出ない。CloudFront のカスタムエラーレスポンスで 403 と 404 を /index.html に向け、ビューアーへ返すステータスを 200 に差し替えるのが定番の対処だ。この設定を入れると本来の 404 も 200 になるため、存在しないパスの扱いはアプリ側で決める必要がある。

SPA の課題と対策

SEO

SPA の初期 HTML は本文を持たない (<div id="root"></div>) ため、内容は JavaScript の実行後にしか現れない。ここで「SPA はインデックスされない」と考えるのは行き過ぎだ。Google はクロール・レンダリング・インデックスの 3 段階で処理し、200 を返したページを描画待ち行列に入れたうえで headless Chromium で JavaScript を実行し、描画後の HTML をインデックスに使うと説明している (2026 年 8 月時点)。

問題は待ち行列に置かれる時間が数秒で済むとは限らない点で、更新の反映が遅れる。加えて JavaScript を実行しないクローラーや SNS のリンクプレビュー生成では、空の HTML と既定のメタタグしか読まれない。

対策:

  • SSR (Next.js): サーバーで HTML を生成
  • SSG: ビルド時に静的 HTML を生成
  • プリレンダリング: クローラー向けに事前レンダリング

SSR や SSG を入れると初期 HTML に本文が入るが、その HTML にイベントを結び付けるハイドレートが終わるまで操作は受け付けられない。表示が速くなっても反応が速くなるとは限らない点が、SSR 化で見落とされやすい。

初期ロードの遅さ

JavaScript バンドルが大きいと、初期表示が遅くなる。

対策:

  • コード分割 (React.lazy): ルートごとにチャンクを分割
  • Tree Shaking: 未使用コードを除去
  • CDN (CloudFront): エッジからの高速配信

メモリリーク

SPA はページ遷移でリロードされないため、イベントリスナーやタイマーの解除忘れがメモリリークの原因になる。React の useEffect のクリーンアップ関数で適切に解除する。

実践的な知識は関連書籍でも得られる。

この記事は役に立ちましたか?

関連用語

関連する記事