Problem
An issue occurred where JavaScript was not executing and the screen was breaking on a specific page. Interestingly, this problem only appeared on the /signup
page among the various paths defined in the middleware matcher.
export const config = {
matcher: [
'/',
'/account',
Path.ITEMS, // Variable used here!
'/blog/:path*',
'/user/:path*',
'/signin',
'/signup',
// ...
]
};
Cause
Explanation from Next.js Official Documentation
According to the Next.js official documentation, middleware matcher values must be statically analyzable at build time, and dynamic values like variables are ignored.
Initially, I thought there would be no problem because Path.ITEMS
was declared as a const
right above the config. However, issues still occurred, so I analyzed the Next.js source code to find the reason.
Next.js Config Analysis Process
Below is part of the actual Next.js code, showing the process used when analyzing SSG or middleware configurations:
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') || {}
// ...
}
}
The important points in this code are:
- First, it reads the configuration file
- It looks for a variable named
config
- It generates and parses an AST (Abstract Syntax Tree)
Looking more closely, Next.js only allows const
declarations:
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;
// ...
}
}
This code shows that values not declared with const
are not extracted.
SWC's AST and Static Analysis
Next.js uses SWC (Speedy Web Compiler) to parse code and generate an AST. In this process, configurations using variables are difficult to analyze statically, making them hard to optimize at build time.
Example of a configuration that allows static analysis:
// ✅ Good example
export const config = {
matcher: [
'/',
'/account',
'/items', // Direct string usage
'/blog/:path*',
]
};
Remaining Questions
I couldn't determine why other pages worked normally while only the /signup
page had issues. This is likely related to peculiarities in Next.js's build process or code splitting.
Conclusion
Care must be taken when using variables in Next.js middleware matcher. Direct string literals should be used for build-time optimization and static analysis.