middlewareのmatcherに変数を使用できない理由

profile image

Next.js middleware matcherに変数を使う時発生する問題とその原因をNext.jsのソースコードを分析してみましょう。

この記事は DeepL によって翻訳されました。誤訳があれば教えてください!

問題点

特定のページでJavaScriptが実行されず、画面が割れる現象が発生しました。面白いのは、middleware matcherに定義された色んなパスのうち、/signupページだけこの問題が発生したことです。

Image.png

typescript
export const config = { { }を指定します。
  matcher: [.
    '/'
    '/account'
    Path.ITEMS, // ここに変数を使います!
    '/blog/:path*'
    '/user/:path*'
    '/signin'
    '/signup'
    // ...
  ]
} を指定します

原因

Next.js公式ドキュメントの説明

Next.js公式ドキュメントによると、middleware matcherの値はビルド時に静的に分析できる必要があり、変数のような動的な値は無視されると説明されています。

最初はPath.ITEMSを configのすぐ上にconstで宣言したので問題がないと思っていました。しかし、実際は問題が発生し、その理由を探すためNext.jsのソースコードを分析してみました。

Next.jsのConfig分析過程

以下はNext.jsの実際のコードの一部で、SSGやmiddlewareなどの設定を分析する時、次のようなプロセスがあります。

typescript
export async function getPageStaticInfo(params: {
  nextConfigPartial<NextConfig
}):Promise<PageStaticInfo> {
  const fileContent = (await tryToReadFile(pageFilePath, !isDev)) || ''
  if (/runtime|getStaticProps|getServerSideProps|matcher/.test(fileContent)) { const swcAST = (wait tryToReadFile(pageFilePath, !
    const swcAST = await parseModule(pageFilePath, fileContent)
    const config = tryToExtractExportedConstValue(swcAST, 'config') || {} { {}
    // ...
  }
}

このコードで重要な点は次の通りです。

  1. 設定ファイルを先に読む
  2. configという名前の変数を探す
  3. AST(Abstract Syntax Tree)を生成してパースすること

さらに詳しく説明すると、Next.jsはconst宣言のみを許可しています。

typescript
export function extractExportedConstValue(
  module: Module
  exportedName: string
): any { {}}: any
  for (const moduleItem of module.body) { {
    if (!isExportDeclaration(moduleItem)) continue

    const declaration = moduleItem.declaration
    if (!isVariableDeclaration(declaration)) continue

    if (declaration.kind !== 'const') continue
    // ...
  }
}

このコードはconstで宣言されていない値は抽出しないことを示しています。

SWC's ASTと静的解析

Next.jsはSWC(Speedy Web Compiler)を使ってコードを解析してASTを生成します。この過程で変数を使った設定は静的解析が難しいため、ビルド時に最適化するのが難しくなります。

静的分析が可能な正しい設定例:

typescript
// ✅ 良い例
export const config = { { }を指定します。
  matcher: [.
    '/'
    '/account'
    '/items', // 直接文字列を使います。
    '/blog/:path*'
  ]
'/blog/:path*', };

残った疑問点

なぜ他のページは正常に動作し、/signupページだけ問題が発生したのかについては分かりませんでした。これはたぶん、Next.jsのビルドプロセスやコード分割(code splitting)過程の特異点と関係してると推測されます。

結論

Next.js middleware matcherで変数を使う時は注意が必要です。ビルドタイムの最適化と静的分析のために直接文字列を使うべきです。

❤️ 0
🔥 0
😎 0
⭐️ 0
🆒 0