猫の手ツール

Step 2: Browser & Architecture

10. SPAとMPAの違い:画面遷移と状態・メモリの考え方

SPAは文書を保ったままJavaScriptで画面やルーティングを管理する構成です。猫の手ツールはURLごとのHTMLを生成し、一つのツール内では表示状態を切り替えます。サイト全体のページ遷移と、編集画面の状態を混同せずに確認しましょう。

1. ページ遷移をHTMLで行うか、JavaScriptで行うか

かつてのWebサイトは、ボタンやリンクをクリックするたびに、ブラウザが「新しいHTMLをください」とサーバーへリクエストを送っていました。サーバーが新しいページを返し、ブラウザがそれをゼロから描画する。こうしたページごとに文書を読み込む構成をマルチページアプリケーション(MPA)と呼びます。画面が白くなるか、速く表示されるかはキャッシュや描画方法にも依存し、MPAだから遅いとは限りません。

対してSPA(Single Page Application)は、読み込んだ文書を保ちながらJavaScriptで画面の切り替えを管理します。必要なデータやコードを追加取得する場合もあります。猫の手ツールではURLごとのHTMLをAstroで生成しており、サイト全体はこの意味のSPAではありません。各ツール内の編集・結果画面はJavaScriptで切り替えています。

2. JavaScriptが「DOM」を直接操作する仕組み

SPAではブラウザ側で画面の状態やルーティングを管理します。DOMを書き換える操作そのものはMPAでも使われるため、ボタンで表示を変えるだけではSPAと区別できません。サーバーから新しいページをもらうのではなく、手元にある部品を入れ替えるイメージです。

これにより、ヘッダーやナビゲーションなどの共通部分を維持したまま、必要な表示を切り替えられます。ページ全体の再取得を減らせる場合がありますが、追加するJavaScriptやAPI通信の量によっては、通信量や表示時間が増えることもあります。

具体的実装:見せる・隠すによる擬似的な遷移

【Before】従来のリンク遷移(物理的なリロードが発生)

<!-- index.html -->
<a href="/result.html">結果を表示</a>
<!-- ⚠️ ページ全体が再読み込みされる -->

【After】SPA的な状態切り替え(リロードなし)

// 物理的な移動はせず、表示状態(State)を切り替える
function goToResult() {
  // 編集エリアを非表示にし、結果エリアを表示する
  document.getElementById('edit-area').style.display = 'none';
  document.getElementById('result-area').style.display = 'block';

  // この例は同じページ内の表示切り替えだけを扱う
  // URLや履歴を変える場合は、直アクセスとpopstateへの対応も必要
}

3. 注意点:SPAが抱える特有の課題

快適なSPAですが、開発時には考慮すべき落とし穴もいくつかあります。

  • SEO(検索エンジン最適化): ページの中身をJavaScriptで生成するため、検索エンジンのクローラーが内容を正しく読み取れない時期がありました(現在はGoogleを中心に改善されていますが、SSRなどの対策が語られる理由です)。
  • 「戻る」ボタンの挙動: 画面を切り替えても履歴を追加しなければ、戻る操作は以前訪れたページへ移動します。History APIを使うなら、pushStateだけでなくpopstateで表示状態を復元する処理も必要です。
  • 初回の読み込み負荷: 大量のJavaScriptを最初に読み込む構成では、初回表示が遅くなる場合があります。SPAが必ず全コードを一括取得するわけではなく、画面ごとのコード分割や遅延読み込みも選択肢です。

4. 実務での役立ち:猫の手ツールでの体験

猫の手ツールでは、1つのツール内で画像選択・編集・結果表示を切り替え、作業中の画像をブラウザ内で扱っています。証明写真の作成は「写真をアップロードし、範囲を選び、ダウンロードする」という一連のフローが非常に密接に関わっています。

同じ文書内ならメモリ上の画像を引き継げます。再読み込みすると通常その参照は失われますが、保持するためにサーバーが必須というわけではなく、IndexedDBなどブラウザ内の保存方法もあります。保持する情報量と、処理後に解放する設計を合わせて考えます。

同じ文書内の編集では画像の参照を引き継げますが、再読み込みや別URLへの移動では状態を失う場合があります。何を保持し、どの操作で破棄するかを決めます。

ツールで確認したい状態の境界

編集画面から結果画面への移動、ブラウザの戻る操作、再読み込みの3つを別々に確認します。画像を保持するほど便利になる一方、元画像・作業用Canvas・保存画像を同時に持つとメモリ消費が増えます。再読み込みで状態を初期化する操作にも役割があります。

本文の表示切り替え例では edit-area と result-area の2要素が存在することを前提にしています。URLまで切り替えるアプリを作る場合は、結果URLへ直接アクセスしたときの初期状態や、元画像がない場合の案内も必要です。

証明写真の4状態は、同じURL内のパネル切り替え

履歴書写真メーカーのsetUI()はupload・loading・edit・resultの4状態を扱います。画像を切り抜いた後にresultを表示しますが、この関数はURLや履歴を変更しません。

function setUI(state) {
  [dropZone, loadingArea, editArea, resultArea].forEach(el => el?.classList.add('hidden'));
  if (state === 'upload') dropZone?.classList.remove('hidden');
  if (state === 'loading') loadingArea?.classList.remove('hidden');
  if (state === 'edit') editArea?.classList.remove('hidden');
  if (state === 'result') resultArea?.classList.remove('hidden');
}

本番関数の型指定を省いた抜粋です。制作解説で切り抜きから保存まで確認した後、再読み込みとブラウザの戻るを別々に試します。パネルの変更だけをSPAのルーティングと呼ばず、静的サイトの配信と区別して考えてください。

まとめ

SPAは、Webを「情報の閲覧場所」から「道具(アプリケーション)の実行場所」へと進化させました。記事を読む画面と、状態を持つ編集画面では必要な設計が違います。MPA、SPA、部分的なクライアント処理を、URL共有・初期表示・操作中の状態という観点で選びます。

URLを共有する情報ページと、入力画像を持つ編集画面では、保存したい状態と直アクセス時の条件が違います。

参考資料

制作時に確かめたこと