Next.js引入next-auth后构建失败:Middleware禁止动态代码评估
Next.js Middleware 运行在受限的 Edge Runtime 环境,该环境禁止 eval、new Function 这类动态代码执行逻辑。构建阶段 Webpack 会对 Middleware 的全量依赖链做静态扫描,只要依赖链中存在不兼容 Edge Runtime 的代码,无论实际运行时是否会执行到对应逻辑,都会直接抛出编译错误。
从错误日志的导入链路可以看到,报错的核心原因是依赖链污染:_middleware.ts → serverFetcherQuery.ts → apollo.tsx → apolloClient.ts 顶层引入了 next-auth/react。next-auth/react 依赖的 @babel/runtime 辅助函数包含动态代码执行逻辑,虽然你在 authLink 中加了 typeof window !== 'undefined' 的浏览器端判断,但静态扫描不会识别运行时判断,依然会将 next-auth/react 判定为 Middleware 的依赖,最终触发编译失败,和你是否在 Middleware 中直接调用 getSession() 没有关系。
优先方案:拆分 Apollo Client 实例,切断跨环境依赖链
不要在同一个 Apollo Client 配置文件中混合客户端专属逻辑和服务端/Edge 逻辑,从根源避免不兼容代码进入 Middleware 依赖链:- 新建
lib/apollo-server.ts,编写仅服务端、Edge 环境使用的 Apollo Client 实例,不引入任何next-auth相关依赖,移除鉴权authLink逻辑,专门给服务端查询、Middleware 中调用的GetThemeServerSide方法使用。 - 保留客户端侧的 Apollo Client 配置,将带
getSession逻辑的authLink放在客户端专属实例中,仅在客户端组件、客户端侧逻辑中导入该实例。
- 新建
临时方案:使用动态导入规避静态扫描
如果暂时不想拆分实例,可以将next-auth/react的顶层导入改为客户端侧的动态导入,绕开构建阶段的静态依赖扫描,修改代码如下:const authLink = setContext(async (_, { headers }) => { if (typeof window !== 'undefined') { if (!token) { // 仅客户端运行时才加载next-auth/react,不会被Middleware静态扫描捕获 const { getSession } = await import('next-auth/react') const session = await getSession() token = session?.accessToken as string } return { headers: { ...headers, authorization: token ? `Bearer ${token}` : '' } } } return { headers: {} } })注意该方案仅绕开构建检查,如果后续在 Edge 环境误触发相关逻辑依然会抛出运行时错误,不建议长期使用。
兼容优化:升级依赖版本
你当前使用的next@12.1.0、next-auth@4.3.4均为较早版本,后续版本对 Edge Runtime 做了针对性兼容优化,将 Next.js 升级到 12.3.x 以上、next-auth 升级到 4.10.x 以上可以减少部分兼容问题,但依然建议配合依赖拆分方案使用,从根源规避同类问题。
内容的提问来源于stack exchange,提问作者majkl zumberi

