问题
在某些页面上,JavaScript 无法执行,屏幕会崩溃。有趣的是,在中间件匹配器定义的不同路径中,只有/signup
页面出现了这个问题。
export const config = {
matcher: [
'/',
/account'、
Path.ITEMS, // 在此使用变量!
'/blog/:path*'、
'/user/:path*'、
/signin'、
/signup'、
// ...
]
};
原因
来自 Next.js 官方文档的解释
根据 Next.js 官方文档,中间件匹配器中的值必须在构建时可静态解析,变量等动态值将被忽略。
起初,我以为既然我在 config 上声明了Path.ITEMS
为 const
,就不会有问题了。但实际上,我遇到了问题,于是我分析了 Next.js 的源代码,以找出原因。
分析 Next.js 中的 config
以下是 Next.js 的部分实际代码,分析 SSG 或中间件配置的过程如下
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') || {}
// ...
}
}
这段代码的要点是
- 首先读取配置文件
- 查找名为
config
的变量 - 创建并解析抽象语法树 (AST)
仔细观察,Next.js 只允许常量
声明
导出函数 extractExportedConstValue(
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 使用 Speedy Web Compiler (SWC) 解析代码并生成 AST。在此过程中,很难对使用变量的设置进行静态分析,因此很难在构建时对其进行优化。
可静态分析的正确配置示例:
// ✅ 示例
export const config = {
matcher: [
'/',
'/account'、
'/items', // 使用直接字符串
'/blog/:path*'、
]
};
剩余问题
我们还没弄明白为什么/signup
页面会出现问题,而其他页面却运行正常。这可能与 Next.js 的构建过程或代码拆分有关系。
结论
在 Next.js 中间件匹配器中使用变量时需要小心。你应该使用直接字符串来进行构建时间优化和静态分析。