SPAでページ遷移後にリロードするとページが表示されない ~webpack-dev-server, netlify~
問題
SPAのWebアプリを開発していて、ページ遷移後にブラウザをリロードするとページが表示されない問題が起きました。
この問題は、ローカルの開発環境(webpack-dev-server)を利用している場合と、デプロイ環境(netlify)どちらでも発生しました。
原因は同じで、対応はそれぞれ別で行う必要がありました。
思い返すと、当たり前だなーと思ったりしますが、自分のWebアプリケーションについての理解が不足してました。
原因とそれぞれの対応を書いておきます。
環境
- react v16.4
- react-router v4
- webpack v4
- webpack-dev-server v3(ローカル環境)
- Babel v7
- netlify(デプロイ環境)
原因
原因は、ページ遷移後のURLに対応するルーティングがサーバーサイドで設定されていないので、404(Not Found)となることでした。
例えば、example.com/
でindex.htmlを返すようにしたアプリの場合で考えます。
ブラウザで、example.com/
にアクセスすると、もちろんindex.htmlが返されて、SPAの場合は概ねbundleしたjsが実行されます。
次に、example.com/hoge/
にアクセスした場合、SPAなのでhistory.pushState
というブラウザAPIを使用してURLを変更して画面が切り替わります。
この時、サーバーへはリクエストが飛びません。
そして、この状態(example.com/hoge/)でリロードすると、サーバーに/hoge
でリクエストが投げられます。
サーバー側で/hoge
のルーティングが無いため、404として処理されるという状況でした。
webpack-dev-serverでの対応
ローカル開発環境(webpack-dev-server)でページ遷移後にリロードすると
Cannot GET /*
とエラーが表示されました。
この場合、webpack-dev-serverの設定でpublicPath
とhistoryApiFallback
を指定しましょう。
const webpack = require('webpack') const path = require('path') module.exports = { // ... output: { // ... publicPath: '/' // ← ここ }, // ... devServer: { historyApiFallback: true // ← ここ } }
これにより、webpack-dev-server上でのアプリのリクエストは404を返す代わりにすべて/index.html
にリダイレクトするようになります。
publicPathを設定すると、アプリケーション内のすべてのアセットのbase pathを指定できます。
historyAPIFallbackは404を/index.htmlにリダイレクトするようになります。
netlifyでの対応
デプロイ環境(netlify)でページ遷移後にリロードすると
同様に、404 Not Foundが表示されます。
この場合は、netlifyのルーティング設定を追加しましょう。
デプロイ対象となるディレクトリに_redirects
ファイルを作成し、以下の内容にします。
/* /index.html 200
これにより、netlifyにデプロイしたアプリのリクエストは404の代わりに/index.html
にリダイレクトするようになります。