🚢

Firebase HostingでNext.jsのDynamic Routing用の設定をする

2022/12/25に公開
1

概要

こんにちは。https://twitter.com/tsux_ssbu です。

この記事はNext.jsをなぜかFirebase Hostingにデプロイしようとしてて、Dynamic Routingがうまくできず時間を溶かしてしまったぼくと同じ状況の人向けにどのように解決したのかが主な内容です。

こまってたこと

Next.jsのDynamic Routingの部分がローカル環境(next dev)では正常に動作するのに、firebase deployをしたら404 not found ページが表示されていたことです。

原因

pages/post/[pid].tsxを実装してる前提で書いてます。

そもそも表示してほしいhtmlファイルが/post/pidのPathにはないので404が表示されていました(404 pageが表示されているので当然といえば当然ですが)。Firebase Hostingでは next build && next exportで生成された静的ファイル(何の設定もしなければoutディレクトリに出力される)がhostingの対象になります。next exportはNext.js アプリを静的な HTML にエクスポートします。詳しくは以下の公式ドキュメントに詳しく書いてます。(next buildは.nextディレクトリに出力されてます)
https://nextjs-ja-translation-docs.vercel.app/docs/advanced-features/static-html-export

next exportではhtmlファイルが出力されるので/post/pid/index.htmlがなければ当然404になります。おそらく何の設定もしていなければoutディレクトリにpost/[pid].htmlが出力されているはずで、これでは/post/pid/にアクセスしてもファイルはありません。(pidの値は可変でもあるので)

ローカル環境では動いていたのに!というのはそもそも出力しているファイルが違い、yarn devではNext.jsの機能であるDynamic Routingを当然なにも設定せず使えるわけです。

解決方法

next.config.jsのtrailingSlash, firebase.jsonのrewritesを設定して解決しました。

① trailingSlashの設定(next.config.js)

trailingSlashをtrueにすることでURL末尾に強制的にスラッシュが付与してくれるもので、/post/pidへのリクエストが自動的にスラッシュが付与されたURLへリダイレクトになります。

設定することで出力されるファイルがpost/[pid].htmlからpost/[pid]/index.htmlになります。
https://nextjs.org/docs/api-reference/next.config.js/trailing-slash

② rewritesの設定(firebase.json)

rewritesを設定することの目的は、複数の URL に対して同じコンテンツを表示するためです。
https://firebase.google.com/docs/hosting/full-config#rewrites

出力されているhtmlファイルはpost/[pid]/index.htmlのみなのでpost/1, post/100へのリクエストでもこちらのファイルを表示したいのでこの設定をする必要があります。

公式ドキュメントが以下のように書いてねっていってるのでそれに従います。

regex URL パターンに一致する URL パスを開こうとすると、ブラウザーには、代わりにdestination URL にあるファイルの内容が表示されます。

こんなかんじ(`・ω・´)

firebase.json
"rewrites": [
        {
            "destination": "/post/[pid]/index.html",
	    "regex": "^/post/([^/]+?)(?:/)?$",
        }]

regexのこのパターンはyarn buildした際に生成された.next/routes-manifest.jsonのdynamicRoutesの箇所をコピペするだけでよさそうです。以下のコードは実際に出力されたやつです。

routes-manifest.json
  "dynamicRoutes": [
    {
      "page": "/post/[id]",
      "regex": "^/post/([^/]+?)(?:/)?$",
      "routeKeys": { "id": "id" },
      "namedRegex": "^/post/(?<id>[^/]+?)(?:/)?$"
    }
  ],

これでデプロイしたらDynamic Routingが機能しました(^-^)

trailingSlashいらんかも

trailingSlashにしたくない場合は、rewritesだけでも問題ないかもです。
/post/[pid].htmlを表示させるかpost/[pid]/index.htmlを表示させるかの違いなだけな気がしてます。確認できてないので知らんけど程度でもあります。

まとめ

Vercelの船に乗りたい!!!

Discussion