SPAの話
どうも。
先日、会社の後輩に「寒すぎてサムライになった」と言ったら「自分はサムゲタンになりました」と返されて、なるほどね、となった茹でコロです。
突然ながら、SPAの話をさせてほしい。
スパではない。エスピーエーである。
経緯
サムゲタンくんとは別の後輩に「SPA / SSRとは何か」との質問を受けた。
SPAは何となく知っていたものの、SSRに至っては言葉すら初耳で回答できなかった。
まじめな先輩である茹でコロは、これではいけないと必死にそれらについて調べ、結果として、なかなかにややこしい概念であることが分かった(それぞれがややこしい概念ではないのだが、セットで理解しようとし、かつSPAから入るとややこしくなる)。
せっかく時間をかけて理解したのでアウトプットしたいのだが、質問者の後輩くんとはタイミングが合わずまだ会話できていない。
すぐアウトプットしないと忘れてしまいそうなので、この場を借りて発散しようというわけである。
SPAとは、の前に
SPAとは何かについて語る前に、そもそもどういった類の話かをお伝えしておこう。
申し遅れたが茹でコロはSEである。
質問者の後輩くんも当然SEなので、SPAはIT用語ということになる。
ネタバレをすると、SPAは「Single Page Application」の略語。
すなわち、IT用語の中でもアプリケーション関連の話である。
スマホアプリなどに使われている技術、と言うと多少興味を持っていただけるだろうか。
IT用語の話にはなるが、SEや趣味でプログラミングをするようなある程度の知識がある方でなくとも理解いただけるように、多少の補足を入れるつもりなので安心してほしい。
逆に、ある程度の知識はあるのでとにかくSPAの概要を素早く理解したい、という方は、別の記事を探したほうがいいかもしれない。
レンダリングとは
SPAを語るにあたり、レンダリングという用語がキーワードになるので事前に説明しておく。
多くのアプリケーションは画面を持っている。
この画面は「html」と呼ばれる言語で書かれたものであることが多い。
厳密には、ユーザが見る画面は「html」で書き出されたもの、という表現が正しい。
何が違うかというと、別にすべてhtmlでプログラミングしているわけではないということだ。
htmlは「静的コンテンツ」と呼ばれる。
つまり、毎回必ず同じデータを表示するもの。
画像や動画なんかも「静的コンテンツ」である。
開くたびに画像の中身が変わっていたらそれはもうホラーの領域だ。
動画はそれ自体が動くのでややこしいが、データとしては変わらないため「静的」に分類される。
しかし、アプリケーションの画面は「静的」でよいだろうか?
同じ画面でも開くユーザが違えば中身も違うべきだろう。全員に同じユーザ名が表示されたり、何度検索しても同じデータしか表示されなかったりしたらおかしな話だ。
にもかかわらずアプリケーションの画面はhtmlで書かれているという。
これはどういうカラクリなのか。
実装方法はいろいろあるが、イメージとして理解してほしいのは、画面にはhtmlとして確定する前の状態がある、ということだ。
たとえば「このエリアにはこんなデータを表示する」という定義だけが書かれたファイルがあるとする。
そこに対して、ユーザごと、あるいは表示タイミングごとにJavaなりC言語なりで処理したデータを埋め込んでから、htmlに書き起こしなおす。
こんなことをしているわけである。
この過程、すなわち処理したデータをhtmlに書き起こすプロセスのことを「レンダリング」と呼ぶ。
レンダリングについて何となくでもイメージを持っていないと、以降の話がまったく理解できなくなるので注意されたし。
MPAとは
では本題に入っていく。
が、SPAについて理解いただくためにはまずMPA (Multi Page Application)について説明する必要がある。本題の序章といったところか。
SPAはMPAの弱点を解決するために生み出された思想である。
つまりMPAのほうが技術としての歴史は古く、ここでは便宜上「従来の実装方式」という言い方をすることにする。
SPA同様、Applicationという単語がついているので、Multi Page方式のアプリケーションの総称であることはもしかしたら想像がつくかもしれない。
Multi Page方式が何かはさておき、その通りである。
MPAのイメージは以下のようになる。
![](https://assets.st-note.com/img/1732844449-tuxFfHoklBKmEynhQVbcXJwa.png?width=1200)
Client(クライアント)とは、ユーザが使っている自前の端末。
Server(サーバ)とは、アプリケーションが置いてある端末。
ざっくりだか上記のようにイメージしてもらえればよい。
ちなみに、なぜか理系は単語の終わりの長音を省略しがちである。サーバーではなくサーバ、ユーザーではなくユーザ、など。
アプリケーションはプログラムそのものや画面を表示するためのデータを必要とするが、それらをすべてクライアント端末にダウンロードしていたら自宅のPCが巨大なものになってしまう。
そのため、プログラム本体やデータを専用のサーバ機に蓄積しておき、クライアントからは都度サーバにアクセスする形で動作しているアプリケーションが多い。
ちなみに、ここで言うアプリケーションはスマホアプリのようなものだけではなく、Web上で動作するサービス / システムなども含んでいる。
たとえばこのnoteも「Webアプリケーション」の一種である。
特に何かをダウンロードしたわけでもないのにnoteを使えるのは、サーバに置いてあるプログラムやデータにクライアントからアクセスして使用しているから、ということになる。
さてさて、前置きが長くなったが、MPAの振る舞いについて。
まずはクライアントからサーバに初回アクセスのリクエストが飛ぶ。
これはどんなアプリケーションでもおおむね同じだ。
そうするとサーバでプログラムが動く。
たとえば「このアクセスは日本からだから、日本語で画面を表示しよう」「最近ログインしていないユーザだから、まずはログインページを表示しよう」など、業務的な処理が行われる。
業務処理を行った結果、次に表示されるべき画面の状態が決定する。
上記の例では、日本語でログインページを表示することが決まったわけだ。
すると「レンダリング」が発生する。
MPAではサーバ内でレンダリングを行い、書き出されたhtmlファイルをクライアントに渡す。
図では「login.html」となっているが、要するにログイン画面を表示するためのhtmlファイルである。
クライアント側はただこのhtmlファイルを眺めるだけでよい。
ログイン画面にはきっと、ユーザIDやパスワードを入力するテキストボックスがあるだろう。
それぞれ入力してログインボタンを押すと、またもやサーバへの通信が発生する。
ここでの業務処理は「入力されたユーザIDやパスワードが正しいか検証」「正しい場合、ユーザの権限を判定して画面に表示する項目 / しない項目を決める」といったものと考えられる。
その結果「menu.html」として書き出すべき情報が決定され、レンダリングが行われる。
クライアント側はまたこのhtmlファイルを眺めて、次に何をするか考えるというわけだ。
まとめると、MPAでは以下の処理を繰り返していることになる。
① クライアント : リクエスト
② サーバ : 業務処理
③ サーバ : レンダリング
④ クライアント : 画面表示
このように、画面ごとにhtmlファイルがレンダリングされるため、アプリケーションとしては複数のページ=Multi Pageを保有していることになる。
これがMulti Page方式のアプリケーション、と呼んだ意味である。
MPAの弱点
ここまでMPAの振る舞いについて説明してきたが、何となくイメージはついたのではないかと思う。
図が非常にシンプルであることからも分かるように、MPAは比較的とっつきやすい処理の流れなのだ。
しかしMPAにも弱点はある。
当然だ。それがなければSPAは生まれていない。
MPAの思想では、画面が変わるごとにレンダリングを行う。
これは別の画面に行く時だけでなく、同じ画面の中で状態が変わっても同じことが起こる。
たとえば、何かの一覧画面で検索ボタンを押したときのことをイメージしてほしい。
検索条件を入力して検索ボタンを押すと、変わるのは一覧データの部分だけ。にもかかわらず、画面全体が再レンダリングされて、list.htmlがサーバから渡される。
これってとても効率が悪い。
だって変わるのは一覧データエリアだけなのに、画面全体を再描画しないといけないから。
効率が悪いと何が起きるかというと、ユーザ離れが起きる。
ボタンを押すたびにグルグルと読み込み中のアイコンが回転するアプリを考えてほしい。嫌になってアンインストールし、別の似たようなアプリを探し始めるのではないだろうか。
そこでエンジニアたちは考えた。
このレンダリングの非効率を解消し、ユーザ離れを防げないだろうか。
そうして発案されたのが「SPA」、この記事の本丸である。
SPAとは
SPAが「Single Page Application」の略語であることは記事前半でネタバレした通りだ。
勘のいい方であれば、先ほど紹介した「Multi Page Application」とちょうど対になる言葉であることが分かるだろう。
そしてさらに勘のいい方であれば、SPAとはつまり1ページだけで構成されたアプリケーションということだな、と想像できるはずだ。
で、ここからはちょっと想像が難しい。
1ページだけでどうやってアプリを作るの?と、当然の疑問が湧く。
たった1ページで何かができるなんて、タイマーかカウンターくらいしか思いつかない。
じゃあSPAはタイマーとカウンター専用の技術なのか!
いやいや、そうだとしたらこんなに流行りませんよと。言い忘れたが、SPAはそれなりに流行している技術なのだ。
この謎について解明する前に、まずはSPAがどのようにしてMPAの弱点を克服しているかを説明しよう。
問題点は、イベント(ここではボタンを押すなど、何かの処理のトリガーとなる操作のこと)ごとに画面が丸ごと再描画されることだった。
直前の状態と差異がない箇所もレンダリングしなおすので、余計なコストがかかっている状態。
これを解消したければ、逆に直前の状態と差異のある箇所だけをレンダリングするようにすればよい。
つまりSPAの基本思想は、画面丸ごとではなく、直前との変更点だけを更新しますよ、ということなのだ。
どこかのアプリやWebサイトで、最下部までスクロールすると一覧の続きが出てくるような動きを見たことがないだろうか?
これもSPAを利用した振る舞いである。
ではこれをどのように実現しているか。ここにSingle Pageたる所以も関わってくる。
いよいよSPAの処理イメージをお見せしよう。
![](https://assets.st-note.com/img/1732847308-rvHQez7kRMVn3EGoDlAbcZ6N.png?width=1200)
まずは初回アクセスのリクエスト。それを受けてサーバは業務処理を始める。ここまではMPAとまったく同じだ。
違うのは、サーバから何が返ってくるかである。
MPAの場合、サーバ側でレンダリング済のhtmlファイルが返却されていた。
しかしSPAでは、index.htmlという(ほぼ)空のhtmlファイルと、複数のjsファイルが返却される。
jsとはJavaScriptの略で、プログラミング言語の一種だ。Android向けのスマホアプリもこの言語を使って実装されている。
詳しいことは割愛するが、ここではhtmlに埋め込んでブラウザ上で動作するプログラムと思ってもらえればよい。
ほかの言語と同様に、JavaScriptではいろいろなことができるが、SPAの文脈においては、htmlを書くための道具と読み替えると分かりやすかろう。レンダリング係などと換言してもよい。
初回アクセスに対してサーバからindex.htmlとjsファイル群が返却されると、初回起動を定義されているjsが早速起動する。ここでは仮に「index.js」と呼ぶことにしよう。
index.htmlは初期段階では(ほぼ)空ファイルであるからして、まだ画面に描画されるべき内容が書き込まれていない。そこでindex.jsが中身を書き込んでいくわけである。先ほどjsをレンダリング係と表現したのはこのためだ。
index.jsがindex.htmlに中身を書き込んで、MPAの事例よろしくユーザIDとパスワードを入力するためのテキストボックスや、ログインボタンが画面に表示される。
結果としてユーザが眺めることになる画面はMPAとSPAで同じものになる仕組みだ。
ユーザがログインボタンを押すと、今度は「login.js」が起動する。
login.jsは入力されたユーザIDとパスワードを読み取り、サーバにリクエストを飛ばす。
するとサーバ側で業務処理が開始されるが、ここでの返却値もMPAとは異なる。
MPAではレンダリングされたmenu.htmlが返却されたが、今回は処理の結果だけが返却される。
たとえば「入力したログイン情報が正しいかったか否か(OK or NG)」や「次画面に表示すべき項目のリスト」などである。
それを受けて、login.jsの続きが動く。
結果がOKだったから次の画面を表示しよう。表示すべき項目のリストは今サーバから受け取ったもの。などの判断が行われ、index.htmlに書き込まれていく。
この際、描画されるのがログイン画面との差分だけであるというのがSPAのポイントだった。
だからたとえば、ブラウザ上部に表示されるヘッダとかサイトロゴとか、ログイン画面とメニュー画面で変わらない箇所に関しては更新されない。
このようにして見た目はメニュー画面に変わったが、表示されているのはindex.htmlのまま。
これを繰り返すことで、index.htmlという同じページを表示したまま、中身を入れ替えて画面が変わったように見せることが可能というわけだ。
これが1ページだけで構成されたアプリケーションの正体である。
この例ではログイン画面からメニュー画面へ、つまり別の画面へ遷移しているので、中身が大きく変わってしまう。
そのためSPAの特徴である直前との差分だけを描画という振る舞いの恩恵は大きくないのだが、MPAの弱点を説明したときのように検索画面を考えてみてほしい。
MPAで検索を実現するために「Serch.java」を作ったとしよう。
このとき実装されるべき処理は、簡易的に以下イメージになる。
① 検索条件欄に入力された値を読み取り
② 条件をもとにデータベースを検索して、対象のデータを抽出
③ 入力値を検索条件欄に書き戻す(イベント前の状態を再現するため)
④ 抽出したデータで結果一覧エリアを描画
⑤ その他、ヘッダやロゴ、ボタンなどを再描画
⑥ htmlをクライアント側に返却して表示
一方、SPAの検索処理「serch.js」が行うべき処理はなんだろうか。
こちらも簡易的に、以下のようになる。
① 検索条件欄に入力された値を読み取り
② 条件をもとにデータベースを検索して、対象のデータを抽出
③ 抽出したデータをクライアント側に返却
④ 表示済のindex.htmlの結果一覧エリアを更新
単純に処理ステップが減ったのが一目で分かるだろう。
これを見ると、MPAに対してSPAが優位にあることがイメージできるはずだ。
SPAの弱点
直前の状態との差分だけをレンダリングすることによってMPAの弱点であった画面遷移時の重さを克服したことは前述の通りだ。
しかし残念ながら、SPAにも弱点はある。
それが、初回ロード時の重さである。
MPAでは、次に表示すべき画面がサーバ上でレンダリングされクライアントに渡される仕組みだった。
つまり、メニュー画面までで止めれば、一覧画面で検索するための処理は不要ということになる。
一方SPAでは、初回ロード時にすべての処理を取得する。
たとえメニュー画面までしか用がなくとも、一覧画面で検索するためのserch.jsを一緒に取ってきてしまうことになる。
つまりSPAは、MPAに比べて初回ロード時にサーバから取得する情報量が多くなるのだ。
それ以降の画面遷移を軽くした代償として、初回ロードが重くなるのである。
初回ロードが重くなると何が起こるか。
やっぱりユーザ離れが起きる。
最初の画面を表示するのに延々と読み込み中のアイコンがグルグルしているサイトを想像してみてほしい。
怒りのままにF5を連打し、しまいにはブラウザを閉じてふて寝することになるのではなかろうか。
頑張ったのにMPAと同じ結果か……と、ここで諦めないのがエンジニアという生き物である。
彼らはさらなる改良策を生み出した。
たとえば、ロードの単位を工夫すること。
茹でコロの先輩に、700画面あるシステムをSPAに作り替えるプロジェクトに参画したことがある人がいる。
何も考えず初回ロードで700画面分のjsを取得するととんでもない重さになりそうなことは、IT業界に携わったことがない方でも想像に難くないだろう。
そこでそのプロジェクトでは、初回ロードですべてを持ってくるのをやめた。代わりに700画面をいくつかの領域に分割し、その領域単位でロードすることにしたそうだ。
これにより、各領域の入口でロード(=重い処理)が発生してしまうが、初回ロード時の負荷を軽減したそうだ。
あるいは、クラウドを活用するという手もある。
要は通信が重いと遅くなるので、全国にエッジと呼ばれる分身体を持つクラウドサーバを活用することによって、物理的な通信経路を短縮し処理時間を削るというものだ。
サービス利用範囲が広ければ広いほどこの手法は有効になる。
たとえばサーバが東京にしかない場合、北海道からアクセスするのに時間がかかるのは明白だ。
しかしクラウドサービスであれば東京にも北海道にもサーバの触手が伸びているので、東京からのアクセスは東京の触手、北海道からのアクセスは北海道の触手が受けるようにすれば通信時間は短縮できる。
そして、SPAという処理方式そのものを改良したのが、次に紹介する「SSR」である。
SSRとは
また新たなアルファベット3文字が登場して辟易している読者も多いだろうが、安心してほしい。茹でコロも気持ちは一緒です。IT業界というのはまったくもって、アルファベット3文字の略称が好きすぎる。
さて、SSRは何の略かというと「Server-Side Rendering」である。
SPAの弱点を克服するために生み出されたこの処理方式は、SPAをベースにしつつも、サーバ側でレンダリングを行うという特性を持つ。
厳密には、SPAの一部をサーバ側のレンダリングで実現することができるというものである。
これにより、初回ロードですべてのjsをダウンロードする必要がなくなり、SPAの弱点であった初回ローディングコストを軽減することができる。
つまりSSRでは、SPAの思想を継承しつつも、以下のような処理を導入しているというわけである。
① クライアント : リクエスト
② サーバ : 業務処理
③ サーバ : レンダリング
④ クライアント : 画面表示
![](https://assets.st-note.com/img/1732865533-f1IcW2QEdMbTnVx5LDk4XG6l.png?width=1200)
……おやおや?
何やら妙な図が出現した。
キャプションに記載の通り、これはSSRの処理イメージである。
しかし、同じような図を見た覚えがある気がする。
![](https://assets.st-note.com/img/1732844449-tuxFfHoklBKmEynhQVbcXJwa.png?width=1200)
そう、MPAの処理イメージである。
MPAは既存の実装方式で、その問題点を解消するために生まれたのがSPAで、さらにその改良版がSSRという話だったはず。
にもかかわらず、MPAとSSRの処理イメージが似通いすぎている。
もちろんSSRはSPAの思想を継承しているので、index.htmlを使いまわして必要なところはjsで書き込むという点は相違があるが、それにしても。
これはいわゆる原点回帰というやつだろうか?
たしかに読み返してみれば、SSRの説明と同じ趣旨のことがMPAの説明としても書かれている。
まとめると、MPAでは以下の処理を繰り返していることになる。
① クライアント : リクエスト
② サーバ : 業務処理
③ サーバ : レンダリング
④ クライアント : 画面表示
ここがSSRのややこしさだ。
もう少し整理して、このややこしさを解きほぐしていこう。
SSRに関する誤解
SSRはSPAの進化系。それは間違いではない。
が、誤解を招く表現であることも理解しておく必要がある。
SSRという単語が新たに出現したとき、違和感を覚えなかっただろうか。
前の2つと一緒に並べてみよう。
MPA = Multi Page Application
SPA = Single Page Application
SSR = Server-Side Rendering
並列すると、SSRの特異さが際立つ。
ほか2つが「Application」であるのに対し、SSRのみ「Rendering」なのだ。
すなわち、表しているものがそもそも違う。
MPAとSPAは「ある方式で実装されたアプリケーション」の話をしている。
一方SSRは「レンダリング方式」の話をしている。
そう、SPAとSSR、あるいはMPAとSSRを比べること自体が誤りなのだ。
ではどのように整理されるのが正しいか。
SSRはレンダリング方式に着目した名称であるようなので、MPAとSPAについても同じように、レンダリング方式を考えてみよう。
MPAは先述の通り、SSRと同じイメージ図で表される。
当然レンダリング方式も同じで、サーバ側で実行されている。
一方SPAは、サーバから取得したindex.htmlと諸々のjsファイルを用いて、クライアント側がhtmlの中身を書き込む方式だった。
すなわち、SPAにおけるレンダリングはクライアント側で実行されていることになる。
ということで、レンダリング方式に着目するとMPAとSSRが仲間、SPAだけが仲間外れということだ。
SPAのようにクライアント側でレンダリングを実行する方式のことを、SSRに対してCSR (Client-Side Rendering) と呼ぶ。
おや? とすると今度は、SSRがSPAの進化系だという話がおかしくなってくるように思える。
上述の通り、SSRはMPAの仲間だという話なので、MPAの進化系なのではなかろうか。
これが本章冒頭で述べた「誤解を招く表現」というところ。
SSRには2種類あるのだ。
正確には、特定の文脈で使われるSSRに別の意味が宿る、と言うべきだろうか。
本来の意味(サーバ側でレンダリングが行われる方式の意)で使われる「SSR」と、SPAの進化系の意味(SPAの思想をベースにしつつ、レンダリングをサーバ側でも実行できるようにしたアプリケーションの意)で使われる、いわば「【SSR】」があるということである。
前章『SSRとは』で説明していたのは【SSR】のほうということだ。
表にまとめると以下のようになる。
【SSR】はSPAの進化系でもあるし、MPAの進化系でもある、ということだ。
![](https://assets.st-note.com/img/1732863290-M3GqWeJcQKNjoplXEOZ1Y4yC.png?width=1200)
ちなみに、SSR方式の強み(=SPAの弱み)として、SEOの強さがある。
SEOとはGoogle検索で上に記事を表示させるための戦略のこと。言い換えると、Googleにどれだけ優秀な記事だと判断してもらえるかである。
SPAでは、初回アクセス時にサーバから返却されるのは(ほぼ)空ファイルであるindex.htmlなので、この時点ではどんなページが分からない。クライアント側でjsが動いて初めてページの中身が確定する仕組みだった。
Googleはjsの処理結果も考慮していると公表しているそうだが、実際はその判断基準はブラックボックス。どれほど正確に処理結果を読み取ってくれているかは誰にも分からない。
したがって、空のhtmlを返却してクライアント側でレンダリングするという手法は、SEO観点では「弱い」のだ。
一方でSSR方式ではサーバ側でレンダリングされたhtmlが返ってくるため、この時点でページの中身が検索エンジンからしても明らかになる。
そのため、正しくコンテンツを評価してもらうことができ、適切にSEOを考えることができるというわけである。
SSRにまつわるややこしさ
つまるところ、SPAとSSRは本来まったく異なるレイヤーの用語だった。
にもかかわらず、【SSR】にSSRと同じ名称を与えてしまったがゆえにこのようなややこしい説明が必要な状態になってしまっているわけである。
茹でコロは本来の意味のSSRを知らないままSPA→【SSR】という系譜に触れてしまったため、理解にたいそう時間を要した。
が、もしCSRとSSRを先に知っていたとしても、SPAの進化系として【SSR】が出現したら、それはそれで目玉をひん剥いていただろう。
アルファベット3文字の略称が好きなら、せめてちゃんと区別がつく略称を与えてくださいね、というIT業界への警鐘を以って、本記事を締めくくることとする。
以上、寒すぎてSomething to Eatになった茹でコロでした。