LoginSignup
3
3

More than 3 years have passed since last update.

SPA のしくみ

Posted at

SPA の仕組みを書いた記事が見当たらなかったので、自分の理解を書いてみます。

普通のページ遷移

SPA じゃない普通の Web ページの場合、まず https://example.com/ にアクセスすると GET / な HTTP リクエストが飛んで、ドキュメントルートにある index.html (静的ページの場合) が返ります。

ここで <a href="/about/"> なリンクを踏むと、https://example.com/about/ に遷移することになり、GET /about/ な HTTP リクエストが飛んでドキュメントルートの about ディレクトリの中の index.html (以下 /about/index.html のように書きます) が返ることになります。

静的 Web サイトのファイル構成

% tree /var/www/html
/var/www/html
├── about
│   └── index.html  # GET /about/ で返るやつ
└── index.html      # GET / で返るやつ

SPA のページ遷移

SPA の場合、例えば react-router の <Link to="/about/"> を踏むと、ブラウサの Hitsory API を使って、実際にページ遷移を行う代わりに、仮想的に https://example.com/about/ へのページ遷移が行われたことにします。このため、GET /about/ な HTTP リクエストは発生しません。

また、その後ブラウザの戻る・進むボタンが押された場合も、ページ遷移は発生せずに JavaScript のイベントが通知されて、router が表示コンポーネントの切り替えを行います。

SPA のファイル構成

% tree /var/www/html
/var/www/html
├── bundle.js
└── index.html

SPA でリロードした場合

問題は、about ページを表示した状態でリロードした場合です。この場合、現在位置は https://example.com/about/ なので、ブラウザは GET /about/ な HTTP リクエストを行います。この際、Web サーバー側に /about/index.html が存在しなければ 404 エラーになってしまいます。

これを防ぐため、Web サーバー側では /about/ などの <Link to="〜"> でリンクされる可能性のある URL (または、ファイルが存在しない URL すべて) のリクエストに対して、/index.html の内容を返すような設定にする必要があります。開発中は webpack-dev-server なら historyApiFallback で簡単に設定できます (create-react-app した場合は勝手にそうなってます) が、ビルドしてデプロイする場合は自分で Web サーバーを設定しないといけません。

また、index.html から bundle.js などに対して相対パスでアクセスしている場合、/about/bundle.js へのアクセスも発生してしまうので、こちらの対応 (絶対パスでアクセスするか <base href="〜"> を設定するなど) も必要です。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3