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: {
  nextConfig: Partial<NextConfig>
}): Promise<PageStaticInfo> {
  const fileContent = (await tryToReadFile(pageFilePath, !isDev)) || ''
  if (/runtime|getStaticProps|getServerSideProps|matcher/.test(fileContent)) {
    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 {
  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のASTと静的分析

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

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

typescript
// ✅ 良い例
export const config = {
  matcher: [
    '/',
    '/account',
    '/items', // 直接文字列を使用
    '/blog/:path*',
  ]
};

残された疑問

なぜ他のページは正常に動作し、/signupページでのみ問題が発生したのかについては解明できませんでした。これはおそらくNext.jsのビルドプロセスやコード分割(code splitting)プロセスの特異性に関連していると推測されます。

結論

Next.js middleware matcherで変数を使用する際は注意が必要です。ビルド時の最適化と静的分析のために、直接的な文字列リテラルを使用すべきです。

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