Next.jsのmiddleware.tsを利用していたら画像が表示されなくなった
TL;DR
middleware.ts は、 public/ やビルド後の _next/ ディレクトリ内のファイルのリクエストに対しても動作するため、利用するときには注意しましょう。
何が起こっていたか
開発中に、画像がリンク切れ表示になっていることに気づきました。
何が原因だったのか
画像のURLをブラウザで確認してみたところ、権限エラーのページが表示されました。
その後、DevToolsのNetworkタブでどうなっているかを確認しました。
画像は /public ディレクトリに置いていて、ビルド時に _next/static ディレクトリにコピーされているものでした。
その画像が307(Temporary Redirect)で権限エラーのページへリダイレクトされていました。
この挙動の問題がどこなのか実装を確認したところ、 middleware.ts で特定のパス以外では権限エラーページへのリダイレクトが行われていることがわかりました。
 middleware.ts はどこまで有効なのか
なぜこうなるのかを調べたところ、middleware.ts は public/ に配置したファイルや _next/ などNext.jsで配信しているファイルにも機能する ことがわかりました。
Matching Pathsより引用すると、優先順位は以下のとおりになっており、5番目に Filesystem routes (public/, _next/static/, pages/, app/, etc.) と書かれています。
headersfromnext.config.jsredirectsfromnext.config.js- Middleware (
 rewrites,redirects, etc.)beforeFiles(rewrites) fromnext.config.js- Filesystem routes (
 public/,_next/static/,pages/,app/, etc.)afterFiles(rewrites) fromnext.config.js- Dynamic Routes (
 /blog/[slug])fallback(rewrites) fromnext.config.js
今回の原因としては、
- 5番目に書かれている内容(Filesystem router)を見逃していた
 - 3番目のMiddleware(= 
middleware.ts)が先にリダイレクト処理を済ませていたため、5番目にたどり着いていなかった 
ということでした。
対処方法
公式ドキュメントのMatcherセクションに記載されているように、 middleware.ts に除外したいパスを記述しました。
export const config = {
  matcher: [
    /*
     * Match all request paths except for the ones starting with:
     * - api (API routes)
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     */
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
}
これにより、画像がリダイレクトされることなく表示されました。
まとめ
技術的な課題に取り組む際には、公式ドキュメントを隅々まで理解することが重要だと再認識しました...。
みなさんも公式ドキュメントを丁寧に読み、フレームワークを最大限に活用できるようになりましょう💪
Discussion