TL;DR
-
next exportは他のウェブフレームワークと違い、単一のhtmlではなくpages単位でhtmlを書き出す - そのため、一般的なSPA向けのサーバー設定では、ブラウザの更新時に404が発生してしまう
- これを回避するには、
/というパスへのリクエスト時に/index.html、/hogeなら/hoge.htmlを探しに行く設定がwebサーバーに必要。下記はNginxの設定例。
location / {
root /hoge/fuga/html;
index index.html;
try_files $uri $uri.html $uri/ /404.html;
}
はじめに
これまでは一番経験があり安定して開発できる技術としてVue2を使ってきたのですが、EoLも見えてきてそろそろ乗り換え…ということで、Next.jsを使い始めました。このとき静的にアプリケーションを配信するためのコマンドnext exportが、これまで触ってきたSPA(たとえばVue)の挙動と違い、そのためwebサーバーの設定で少し困ったので、メモしておきます。
Vueのビルドと違うところ
Vueの場合index.htmlはひとつですが、next exportはpagesに配置されているコンポーネントの数だけhtmlが作成されます。SSG用のコマンドなので事前に全ページのHTMLを作成しておく、という思想なのでしょう。
たとえば
pages
├── _app.tsx
├── sample.tsx
└── index.tsx
こんな構造だと、next exportの結果は
dist
├── 404.html
├── _next
├── sample.html
└── index.html
こんな感じになるはずです。
困ったこと
上記でも、ローカルで開発している限りは、特に困ることがありません。しかしこのビルド結果をVueだとかと同じ感覚でデプロイすると(=単なるwebサーバーでの配信+index.htmlへのフォールバック)、ページリロード時に404となったり、トップページが表示されたりと、期待した挙動になりません。
期待した挙動にならない理屈
- CSRで
/sampleを表示しているとする - 更新すると、webサーバーは
sampleというファイルを探しに行く(が、存在しない) - 存在しないのでindex.htmlにフォールバックする(が、ページが
/sampleとしてレンダリングされない!)
2まではVueのルーティングでも起こる問題ですが、3はNext.jsで発生する問題です。
Next.jsでは、/sampleを更新する際は/sample.htmlを見に行かせる設定が必要となります。
Nginxの設定
下記のように設定することで、/hogeというURLをリクエストして/hogeが存在しなければ、/hoge.htmlを探しに行かせることができます。また、/へのリクエストは/index.htmlに流す、という設定も必要です。下記が設定ファイルの例です(冒頭と同じ)。
location / {
root /hoge/fuga/html;
index index.html;
try_files $uri $uri.html $uri/ /404.html;
}
終わりに
インターネッツを探しても、あんまり記事が見つからなかったのですが、next exportをNginxで運用…というのはあんまりやるべきじゃないのでしょうか?
それとももっと良い方法がある?webサーバー+CSRがもう流行っていない?CRAを使うべき?
知見のある方はコメント頂けるとうれしいです。。。