Next.js 12.1.6配置experimental.runtime报错需启用reactRoot搭配React18
问题根因
- 报错
experimental.runtime requires experimental.reactRoot to be enabled along with React 18的核心原因是Next 12.1.6 dev模式的依赖检测bug:你的Next应用托管在./src/client子目录,React、react-dom依赖被提升到了项目根目录的node_modules中,dev模式启动热重载时,webpack配置初始化阶段的React版本检测逻辑不会正确向上遍历查找被提升的依赖包,误判当前环境React版本低于18,且未自动开启reactRoot特性,直接抛出错误。生产构建(npm run build)使用独立的依赖解析逻辑,能正确识别根目录的React 18版本,因此构建流程可正常运行。 - 同版本依赖的全新空白项目不触发报错,是因为空项目的Next、React、react-dom都安装在同一级目录下,不存在子目录托管、依赖提升的场景,dev模式可直接读取到正确的React版本,自动开启
reactRoot特性,不会触发校验拦截。 - 切换到
next@canary后出现的HookWebpackError: The "to" argument must be of type string. Received undefined错误,是canary版本对跨层级自定义distDir配置的路径解析bug,和React Server Components本身的能力无关。
修复方案
方案1:使用Next 12.1.6稳定版(优先选择,无已知兼容bug)
- 修改
next.config.js,显式开启reactRoot配置,跳过dev模式的自动版本检测逻辑:
const nextConfig = { distDir: '../../.next', reactStrictMode: true, experimental: { runtime: 'nodejs', serverComponents: true, concurrentFeatures: true, reactRoot: true, // 显式声明开启React 18 root API }, }; module.exports = nextConfig;
- 修改NestJS中启动Next服务的代码,将Next项目目录从相对路径改为绝对路径,避免Next内部路径解析、依赖查找逻辑出错:
import { Injectable, OnModuleInit } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import createServer from 'next'; import { NextServer } from 'next/dist/server/next'; import { Request, Response } from 'express'; import { join } from 'path'; @Injectable() export class ViewService implements OnModuleInit { private server: NextServer; constructor(private configService: ConfigService) {} async onModuleInit(): Promise<void> { try { this.server = createServer({ dev: this.configService.get<string>('NODE_ENV') !== 'production', dir: join(process.cwd(), 'src/client'), // 传入绝对路径指向Next项目目录 }); await this.server.prepare(); } catch (error) { console.error(error); } } handler(req: Request, res: Response) { return this.server.getRequestHandler()(req, res); } }
- 如果上述修改后仍报React版本检测错误,在项目根目录执行以下命令,将根目录的React依赖软链到Next子目录,保证Next可直接读取到正确版本:
npm link ./node_modules/react ./node_modules/react-dom --prefix ./src/client
方案2:使用next@canary版本(需使用最新RSC特性时选择)
- 移除
next.config.js中跨层级的distDir配置,避免canary版本的路径解析bug:
const nextConfig = { // 删除distDir: '../../.next'配置 reactStrictMode: true, experimental: { runtime: 'nodejs', serverComponents: true, concurrentFeatures: true, }, }; module.exports = nextConfig;
- 修改package.json中的build脚本,在Next构建完成后手动移动构建产物到目标路径:
"build": "nest build && cd src/client && next build && mv .next ../../.next"
- 同方案1第二步,将Next启动的dir参数改为绝对路径,保证路径解析正确。
验证步骤
- 删除项目根目录、
src/client目录下所有.next缓存文件夹 - 重新执行
npm run start:dev,校验dev服务是否正常启动 - 执行
npm run build校验生产构建流程是否正常,React Server Components能力是否可正常使用
内容的提问来源于stack exchange,提问作者ORLVNI
相关产品推荐
相关产品推荐

