t28.dev

Next.jsのSSGしたビルド成果物をFirebase, GCSでホスティングする方法

2021/7/19
Tech

なにこれ

Next.js の SSG (Static site generate) によるビルド成果物を Firebase(hosting)、GCS (Google Cloud Storage) にデプロイするためにやっていることの共有


はじめに

本記事が言う要件とは「https://domain.com/another への HTTP リクエストで https://domain.com/another.html へ到達して欲しい」ということです。

Next.js の SSG

Next.js は SSG 機能 (Static HTML Export) を使用することで、ページ毎の html ファイルを予め出力することが出来ます。 index.js, another.js というページがあれば、それぞれ index.html, another.html が出力される感じですね(それ以外の出力は SPA 用の js とか静的ファイル)。

$ ls pages
_app.js		another.js	api		index.js
$ ls out
404.html	_next		another.html	favicon.ico	index.html	vercel.svg

html へアクセス後の SPA としてのルーティング

仮に、https://domain.com みたいな感じで root (pages/index.js) にアクセスしたとします。 その後 next/link 等 Next.js の router で “pages/another.js” に画面遷移を行うと、path は /another になります。 この URL の状態(https://domain.com/another)でブラウザーリロードを行うと、another.html に HTTP リクエストが届かないため 404 になってしまいます。

Next.js の SSG のビルド成果物をデプロイするときは、上記の対応も併せて行う必要があります。

to Firebase Hosting

結論

私は firebase.json 内で以下 2 つの設定を行っています。

{
  "hosting": {
    "cleanUrls": true,
    "trailingSlash": false
  }
}

説明

Firebase Hosting では firebase.json でホスティング動作を構成することが出来ます (ref. ホスティング動作を構成する)。

cleanUrls

ref. .html 拡張子を制御する

要件に対してお誂え向きな設定項目があって助かります。

true の場合、Hosting はアップロードされたファイルの URL から拡張子 .html を自動的に削除

してくれるので、これで要件が達成できます。

trailingSlash

ref. 末尾のスラッシュを制御する

cleanUrls だけで本来の要件は達成出来ますが、私は併せて trailingSlash も設定しています。

false の場合、Hosting は URL のリダイレクトで末尾のスラッシュを削除します。

デフォルト(未設定)の場合、 /another/another.html/another//another/index.html へ解決する挙動になり、少しややこしいです。 trailing slash のあり・なしで期待するルーティングの挙動が異なるケースは殆どないので、挙動を統一するために false を設定しています。

to GCS (Google Cloud Storage)

結論

私は next.config.js 内で以下の設定をして、

module.exports = {
  trailingSlash: true,
};

GCS で MainPageSuffix を index.html に設定しています。

説明

GCS では Firebase Hosting のようなルーティングに関する細かい設定が行えないため、ビルド成果物に対する設定で対処しています。

trailingSlash (Next.js)

ref. Trailing Slash

trailingSlash: true の状態で SSG を行うと、path は ファイル名ではなくディレクトリ名で表現され、出力される html ファイルの名前は index.html になります。

$ ls out
404.html	_next		another   favicon.ico	index.html	vercel.svg
$ ls out/another
index.html

MainPageSuffix、Folders (GCS)

本要件のためというよりは静的ウェブサイトを設置する Web サーバーの基本設定ですが、MainPageSuffix を index.html に設定して インデックスページを設定します 。 これによって GCS のサブディレクトへのアクセスの挙動は

  • HTTP GET /subdirectory => /subdirectory/index.html へ 301
  • HTTP GET /subdirectory/ => /subdirectory/index.html の中身を返却する 200

となる(ref. フォルダ )ため、前述の Next.js のtrailingSlashの設定と併せることで要件が達成できます。

ちなみに/subdirectory/index.html にいるときに Next.js の router を使って pages/another-dir.js にアクセスしようとすると、next.config.js のtrailingSlash: true に従って、/another-dir/ にアクセスしてくれるため、 trailing slash のあり・なしで困った挙動差が!みたいなことにはなりません。

余談ですが、Google 的には 日本語記事だとサブディレクトリ と書いてある部分が英語記事だとフォルダー(Folders) なんですね。