Problem
On certain pages, JavaScript would not execute and the screen would crash. Interestingly, the issue only occurred on the /signup
page out of several paths defined in the middleware matcher.
export const config = {
matcher: [
'/',
'/account',
Path.ITEMS, // Use variables here!
'/blog/:path*',
'/user/:path*',
'/signin',
'/signup',
// ...
]
};
Cause
Explanation from the official Next.js documentation
According to the official Next.js documentation, the values of the middleware matcher must be statically resolvable at build time, and dynamic values such as variables are ignored.
Initially, I thought that since I declared Path.ITEMS
as const
right above config, I shouldn't have a problem. But in reality, I had a problem, and I analyzed the source code of Next.js to find out why.
Analyzing config in Next.js
Below is some of the actual code of Next.js, and the process of analyzing the configuration of SSG or middleware is as follows
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
- It reads the configuration file first
- Finds a variable named
config
- Creates and parses an Abstract Syntax Tree (AST)
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 that are not declared as const are
not extracted.
SWC's AST and static analysis
Next.js uses the Speedy Web Compiler (SWC) to parse your code and generate ASTs. During this process, settings that use variables are difficult to statically analyze, making them difficult to optimize at build time.
Example of a correct configuration that can be statically analyzed:
// β
Good example
export const config = {
matcher: [
'/',
'/account',
'/items', // use direct string
'/blog/:path*',
]
};
Questions remaining
We haven't figured out why the /signup
page was broken while the other pages worked fine. It probably has something to do with a quirk in Next.js' build process or code splitting.
Conclusion
You need to be careful when using variables in the Next.js middleware matcher. You should use direct strings for build time optimization and static analysis.