【Next.js/Firebase】trailingSlashとは何か? “cleanUrls”: trueの関係と違い。最適な設定は?(output: ‘export’のベストプラクティス)

firebase-prograshi(プロぐらし)-kv Firebase
記事内に広告が含まれていることがあります。

Next.jsのtrailingSlashとは何か?

Next.jsのtrailingSlashオプションは、URLの末尾にスラッシュ(/)を付けるかどうかを制御する設定です。

値のfalse/trueを切り替えることで出力するファイル構造とブラウザのURLの書き換えを行います。デフォルトはfalseです。

設定は「next.config.js」で行います


デフォルトの挙動(trailingSlash: false)

Next.jsのデフォルト設定では、末尾のスラッシュは自動的にスラッシュ無しにリダイレクトされます。

例えば、 /about/ にアクセスすると、/about へリダイレクトします。

状態アクセスURL実際の結果
デフォルト (false)/contact//contact にリダイレクト
有効化 (true)/contact/contact/ にリダイレクト
Point

trailingSlash: trueは主に、静的エクスポート(output: ‘export’)設定時に使います。


trailingSlash: trueはいつ使う?静的エクスポート(output: 'export')

trailingSlash: trueは、Next.jsで静的なHTMLファイルを生成する(SSGにする)場合に需要となります。

false(デフォルト)では、 /about.html というファイルを生成しますが、trueにすることで /about/index.html というディレクトリ構造で生成するようになります。

さらに、アクセスしたときに、/aboutを/about/に統一することで、確実にindex.htmlを表示することができます。

AWS S3やFirebase Hostingなどの多くのWEBサーバーでは、/about/ というURLでアクセスした際に /about/index.html を探す仕組みになっているため、静的サイトとして書き出す場合は true に設定するのが一般的です。


trailingSlash: trueの設定方法

trailingSlash: trueにする場合は、next.config.tsに以下のように「trailingSlash: true」を記述します。

// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
  
  //SSGで静的HTMLを生成 
  output: 'export',
  trailingSlash: true, //⇚これ
  images: {
    unoptimized: true,
  },
};

export default nextConfig;


Firebase Hostingの”trailingSlash”: true

Next.jsの静的エクスポート(output: 'export')を利用する場合、Next.js側の設定とFirebase側の設定を一致させるのが鉄則です。

つまり、Firebase Hostingの設定にも「”trailingSlash”: true」を追加します。

"hosting": {
    "public": "out",
    "trailingSlash": true, ※⇚これ
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**",
      "scripts/**" 
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  },

これで、firebase hostingで公開中のサイトにアクセスしたときに、すべてのURLの末尾にスラッシュを強制し、スラッシュなしでアクセスするとリダイレクトします

注意点

もし、Next.jsのtrailingSlashとfirebase hostingのtrailingSlashの設定がずれていると、ブラウザで無限にリダイレクトを繰り返すリダイレクトループが発生し、ページが表示されなくなります。


Firebase Hostingの”cleanUrls”: true

Firebase HostingでURLを制御するオプションには「”cleanUrls”」もあります。

「”cleanUrls”: true」にすることで、ファイル末尾の「.html」 をURLから取り除くことができます。

例えば、サーバー上の about.html というファイルにアクセスするときに「/about.html」ではなく、「/about」としてアクセスします。(.htmlありを、なしに統合)

Firebase Hostingにおいて、.html を直接叩いた時の挙動は以下のようになります。

設定の組み合わせ/about.html を叩いた結果
cleanUrls: true + trailingSlash: false/about になる
cleanUrls: true + trailingSlash: true/about/ になる
cleanUrls: false/about.html のまま表示される(リダイレクトなし)


なお、Next.jsでtrailingSlash: trueにするとディレクトリ構造が「/about.html」から「/about/index.html」になります。

この場合、cleanUrls の設定に関わらずルートの index.html は常に消えます

これは、ほとんどの近代的なWebサーバー(Firebase含む)が、ドメイン直後の index.html を「サイトの顔」として扱い、URL上で省略して表示するためです。

設定の組み合わせ/index.html (ルート) の結果/about/index.html (サブ) の結果
両方 true (推奨)example.com/example.com/about/
clean: true / slash: falseexample.com/example.com/about
clean: false / slash: trueexample.com/example.com/about/
両方 false (初期値)example.com/example.com/about


output: ‘export’のベストプラクティス

Next.jsで「output: ‘export’」としてSSGとした場合のベストプラクティスは、Next.jsとFirebase Hostingの両方でtrailingSlashをtrueにすることです。

更に、以下の2つも追加します。

【追加1】Linkタグに prefetch={false}属性を追加

【追加2】Hostingにredirectを追加


Linkタグに prefetch={false}属性を追加

Next.jsのRoute Appは表示高速化のためにページ内に含まれているLinkタグを読み込んでプリフェッチしようとします。

「output: ‘export’」としてSSGとした場合、プリフェッチ用のファイルが生成されていないので404エラーが発生します。

これを防ぐためにLinkタグに prefetch={false}属性を追加します。

詳しくは下記をご参考ください。


Hostingにredirectを追加

Firebaseのデフォルトでは404ページにアクセスしたときに「404」と表示されてそのままになってしまいます。

オプションのrewriteを追加し、存在しないページにアクセスしたときはトップにリダイレクトするように設定すると親切です。

"hosting": {
    "public": "out",
    "trailingSlash": true,
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**",
      "scripts/**" 
    ],
    "rewrites": [         ※⇚これ
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  },

source": "**"
「全てのパス(ディレクトリやファイル名)」を対象にするというワイルドカードです。

destination": "/index.html"
対象のパスにアクセスがあった際、サーバーの内部で /index.html の中身を返します。

独自の404ページを表示したい場合は不要

もし、独自の404ページを表示したい場合は rewriteオプションは不要です。

タイトルとURLをコピーしました