わしのlog

プログラミングとかバイクとか。

react-routerを使ったアプリケーションでURL直叩き(or F5)すると404になる

はじめに

こんにちは、だいきちです。
今回はreact-routerを使用し、serveを使ってローカルにサーバを立てた時
/以外のURLで404となってしまう現象について書きます。
恐らくタイトルだけ見て「ははぁ~ん?」となった方もいるでしょう
ですが、私は初学者ゆえわからず・・・
結果としては公式ドキュメントちゃんと読めよという話でした。(自戒

環境

  • create-react-app(CRA) : 2.1.3
  • react-router: 4.3.1
  • serve: 11.0

なぜ404?

この辺りを参照。
qiita.com

teratail.com

要するに、サーバ側にrewriteの設定が必要な訳ですね。
2つ目のQ&Aを見るとわかると思いますが、サーバ側が返しているのはあくまでindex.html
react-routerがURLに対応するコンポーネントを切り替えているだけなので、
URLにマッチするリソースは存在しません = 404となるわけですね。
なるほど、わかりやすい。
Reactって動的にindex.htmlを書き換えてるだけですもんね、仮想DOMを使って。
(間違ってたらスミマセン)

解決策

で、本題の解決策なんですが、ぶっちゃけるとserveでは解決してません。
serveのREADME見るとそれっぽいこと は書いてあるのですが
まず
create-react-appの公式ドキュメントにそれっぽいことは書いてないか?
という疑問が浮かんだので、調べると...
ありました
なになに...

If you use routers that use the HTML5 pushState history API under the hood (for example, React Router with browserHistory), many static file servers will fail.  
google様訳: HTML5 pushState history APIを内部で使用するルーター(たとえば、browserHistoryを持つReact Router)を使用すると、多くの静的ファイルサーバーが失敗します。


ですよねー

と、いうわけで下の方に行くと、Expressを使用した例が。
素直にExpressをインストールして使用しました。
npm install express --save
その後、プロジェクトルートにserver.jsを作成。
後は公式ドキュメントのソースをコピペ。

const express = require('express');
const path = require('path');
const app = express();

app.use(express.static(path.join(__dirname, 'build')));

app.get('/*', function(req, res) {
  res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

app.listen(9000);

npm run build でアプリケーションをビルド。
node server.js でサーバ起動。http://localhost:9000に接続すれば
アプリケーションの起動が確認できると思います。
後はURLを直叩きしても404にならない優しい世界をご堪能下さい。

余談

先ほどserveでは実装しませんでしたが、やはりconfigっぽいのを定義すればいけるんじゃないでしょうか。
(下記参照。※検証はしていません。)
spectrum.chat

まとめ

最初にも書きましたが、公式ドキュメントは読みましょう。
もう一度言います、公式ドキュメントは読みましょう

現場からは以上です。