news 2026/9/12 23:17:35

Nx 工作区中 Next.js 15 升级到 Next.js 16 的完整迁移指南:基于 Nx 22.2 自动化迁移指令的实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Nx 工作区中 Next.js 15 升级到 Next.js 16 的完整迁移指南:基于 Nx 22.2 自动化迁移指令的实战解析

Nx 工作区中 Next.js 15 升级到 Next.js 16 的完整迁移指南:基于 Nx 22.2 自动化迁移指令的实战解析

【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx

Next.js 16 引入了大量破坏性变更(Async Request APIs、Turbopack 默认化、Middleware 重命名为 Proxy 等),在 Nx 多项目工作区中手动逐项目升级成本极高。本文以 Nx 官方随迁移生成器发布的 ai-instructions-for-next-16.md 为骨架,完整解析全部 13 类破坏性变更的修改要点、可复制的代码示例与验证流程,并结合 Nx 仓库中的迁移注册机制与 Agent 执行框架,帮助你系统、安全地完成升级。读完本文,你将掌握从项目识别、依赖升级、分类改写、构建验证到回退排障的完整实战方案。

一、这份迁移指令在 Nx 中的定位与工作机制

在 Nx 仓库中,这份文档并不是一份普通的散落说明,而是被正式注册为迁移生成器的"提示词(prompt)"。查看 packages/next/migrations.json 可以看到:

"update-22-2-0-create-ai-instructions-for-next-16": { "cli": "nx", "version": "22.2.0-beta.1", "requires": { "next": ">=16.0.0" }, "description": "Create AI Instructions to help migrate users workspaces to Next.js 16.", "prompt": "./dist/src/migrations/update-22-2-0/ai-instructions-for-next-16.md" }

同一版本还通过packageJsonUpdates声明了配套的依赖升级目标(见 migrations.json):next升级到~16.0.1eslint-config-next升级到^16.0.1

从源码结构看,Nx 在packages/nx/src/command-line/migrate/agentic/下实现了整套"Agent 化迁移"机制(如 prompt-migration.ts),迁移生成器的prompt字段会被读取并注入到迁移任务的系统上下文中,交给 LLM/Agent 按指令逐条执行。这正是本文档"Notes for LLM Execution"一节存在的意义:它不仅是给人看的升级手册,更是给 Agent 看的、可逐步执行的任务说明书。

在动手之前,请先理解本迁移的适用范围:目标是把 Nx 工作区中基于 Next.js 15 的项目升级到 Next.js 16,工作方式是按破坏性变更类别逐项系统推进,而不是一次性盲目改动。

二、迁移前检查清单(Pre-Migration Checklist)

1. 识别所有 Next.js 项目

nx show projects --with-target build | xargs -I {} nx show project {} --json | jq -r 'select(.targets.build.executor | contains("next")) | .name'

或者直接搜索 Next.js 配置文件:

find . -name "next.config.*" -not -path "*/node_modules/*"

nx show projects是 Nx 22 起推荐的项目清单命令,配合nx show project <name> --json可以精确筛选出 build target 使用 next 相关 executor(如@nx/next:build@nx/next/plugin推断出的任务)的项目。注意:@nx/next:buildexecutor 在仓库中已被标记为弃用并将随 Nx v24 移除,建议通过nx g @nx/next:convert-to-inferred迁移到@nx/next/plugin推断式插件(参见 packages/next/src/executors/build/schema.json),但无论哪种方式,升级到 Next.js 16 都需要完成本文的改动。

2. 更新依赖包

npm install next@latest react@latest react-dom@latest npm install -D @types/react @types/react-dom # if using TypeScript

3. 核验最低环境要求

  • Node.js 20.9+(Node.js 18 不再受支持)
  • TypeScript 5.1.0+
  • 浏览器支持:Chrome 111+、Edge 111+、Firefox 111+、Safari 16.4+

三、按类别的迁移步骤

1. 异步请求 API(Async Request APIs,最大破坏性变更)

这是 Next.js 16 影响面最大的变更:所有动态请求 API 都变为异步

需要重点检索的模式:

  • 服务端组件中的cookies()用法
  • 服务端组件中的headers()用法
  • draftMode()用法
  • page、layout、route handler 和 metadata 文件中的params
  • page 组件中的searchParams
1.1 使用 params 的 Page 组件
// BEFORE (Next.js 15) export default function Page({ params }) { const { slug } = params; return <h1>{slug}</h1>; } // AFTER (Next.js 16) export default async function Page(props) { const { slug } = await props.params; return <h1>{slug}</h1>; }

操作清单:

  • 将所有使用params的 page 组件改为 async
  • 在访问props.params前添加await
  • 如适用,更新 TypeScript 类型
1.2 使用 searchParams 的 Page 组件
// BEFORE (Next.js 15) export default function Page({ searchParams }) { const query = searchParams.q; return <Results query={query} />; } // AFTER (Next.js 16) export default async function Page(props) { const searchParams = await props.searchParams; const query = searchParams.q; return <Results query={query} />; }

操作清单:

  • 将所有使用searchParams的 page 组件改为 async
  • 在访问props.searchParams前添加await
1.3 使用 params 的 Layout 组件
// BEFORE (Next.js 15) export default function Layout({ children, params }) { const { locale } = params; return <div>// BEFORE (Next.js 15) export async function GET(request, { params }) { const { id } = params; return Response.json({ id }); } // AFTER (Next.js 16) export async function GET(request, props) { const { id } = await props.params; return Response.json({ id }); }
1.5 cookies() 与 headers()
// BEFORE (Next.js 15) import { cookies, headers } from 'next/headers'; export default function Page() { const cookieStore = cookies(); const headersList = headers(); const theme = cookieStore.get('theme'); const userAgent = headersList.get('user-agent'); return <div>...</div>; } // AFTER (Next.js 16) import { cookies, headers } from 'next/headers'; export default async function Page() { const cookieStore = await cookies(); const headersList = await headers(); const theme = cookieStore.get('theme'); const userAgent = headersList.get('user-agent'); return <div>...</div>; }
1.6 draftMode()
// BEFORE (Next.js 15) import { draftMode } from 'next/headers'; export default function Page() { const { isEnabled } = draftMode(); return <div>{isEnabled ? 'Draft' : 'Published'}</div>; } // AFTER (Next.js 16) import { draftMode } from 'next/headers'; export default async function Page() { const { isEnabled } = await draftMode(); return <div>{isEnabled ? 'Draft' : 'Published'}</div>; }
1.7 带 params 的 generateMetadata
// BEFORE (Next.js 15) export async function generateMetadata({ params }) { const { slug } = params; return { title: slug }; } // AFTER (Next.js 16) export async function generateMetadata(props) { const { slug } = await props.params; return { title: slug }; }
1.8 自动化迁移

运行 Next.js 官方 codemod 完成自动化改写:

npx @next/codemod@canary upgrade latest

生成类型辅助工具以获得更安全的迁移(Next.js 15.5+):

npx next typegen

这会生成PagePropsLayoutPropsRouteContext类型辅助。它也是后续解决 params 类型报错的关键手段。

2. 图像生成函数(Image Generation Functions)

检索模式generateImageMetadata、opengraph-image 或 twitter-image 文件中的default function Image

// BEFORE (Next.js 15) export function generateImageMetadata({ params }) { const { slug } = params; return [{ id: '1' }]; } export default function Image({ params, id }) { const slug = params.slug; return new ImageResponse(/* ... */); } // AFTER (Next.js 16) export async function generateImageMetadata({ params }) { const { slug } = await params; return [{ id: '1' }]; } export default async function Image({ params, id }) { const { slug } = await params; const imageId = await id; return new ImageResponse(/* ... */); }

操作清单:

  • generateImageMetadata函数改为 async
  • 将 Image 组件改为 async
  • paramsid的访问都添加await

3. Sitemap 生成

检索模式:带id参数的sitemap函数。

// BEFORE (Next.js 15) export default async function sitemap({ id }) { const start = id * 50000; // ... } // AFTER (Next.js 16) export default async function sitemap({ id }) { const resolvedId = await id; const start = resolvedId * 50000; // ... }

4. Turbopack 配置

Turbopack 现在是开发环境的默认打包器。

检索模式:package.json scripts 中的--turbo--turbopack标志、next.config 中的turbopack配置。

4.1 移除显式 Turbopack 标志
// BEFORE (Next.js 15) { "scripts": { "dev": "next dev --turbo" } } // AFTER (Next.js 16) - Turbopack is default { "scripts": { "dev": "next dev" } }
4.2 需要时回退到 Webpack
{ "scripts": { "build": "next build --webpack" } }
4.3 将 Turbopack 配置移出 experimental
// BEFORE (Next.js 15) const nextConfig = { experimental: { turbopack: {/* options */}, }, }; // AFTER (Next.js 16) const nextConfig = { turbopack: {/* options */}, };
4.4 更新 Sass 导入(Turbopack 特有)
/* BEFORE */ @import '~bootstrap/dist/css/bootstrap.min.css'; /* AFTER - Remove tilde prefix */ @import 'bootstrap/dist/css/bootstrap.min.css';

操作清单:

  • 从 scripts 中移除--turbo--turbopack标志
  • turbopack配置从experimental提升到根级
  • 移除 Sass 导入中的波浪号(~)前缀
  • 需要 Webpack 时添加--webpack标志

5. Middleware 重命名为 Proxy

检索模式middleware.tsmiddleware.js文件。

# Rename the file mv middleware.ts proxy.ts
// BEFORE (middleware.ts) export function middleware(request) { // ... } // AFTER (proxy.ts) export function proxy(request) { // ... }

配置项更新

// BEFORE { skipMiddlewareUrlNormalize: true; } // AFTER { skipProxyUrlNormalize: true; }

重要proxy中不再支持 Edge runtime,它现在使用 Node.js runtime。

操作清单:

  • middleware.ts/js重命名为proxy.ts/js
  • 将导出的函数名从middleware改为proxy
  • 更新配置项名称
  • 从 proxy 文件中移除 Edge runtime 用法

6. 并行路由的 default.js 要求

检索模式:app 目录中以@开头的目录(并行路由插槽)。

所有并行路由插槽现在都要求有显式的default.js文件。

// Create app/@modal/default.tsx for each parallel route slot import { notFound } from 'next/navigation'; export default function Default() { notFound(); // or return null }

操作清单:

  • 找出所有并行路由插槽(app/@*/
  • 为每个没有default.tsx的插槽创建该文件

7. 图像优化变更

7.1 带查询字符串的本地图像
// Now requires explicit configuration <Image src="/assets/photo?v=1" alt="Photo" width="100" height="100" />
// next.config.js module.exports = { images: { localPatterns: [ { pathname: '/assets/**', search: '?v=1', }, ], }, };
7.2 默认值变更

如果业务需要旧的默认行为,在next.config.js中补充:

module.exports = { images: { // minimumCacheTTL changed from 60 to 14400 seconds minimumCacheTTL: 60, // Value 16 removed from default imageSizes imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], // qualities now defaults to [75] only qualities: [50, 75, 100], // Local IP now blocked by default dangerouslyAllowLocalIP: true, // only for private networks // Maximum redirects changed from unlimited to 3 maximumRedirects: 5, }, };
7.3 弃用的 images.domains
// BEFORE - Remove this module.exports = { images: { domains: ['example.com'], }, }; // AFTER - Use remotePatterns instead module.exports = { images: { remotePatterns: [ { protocol: 'https', hostname: 'example.com', }, ], }, };

操作清单:

  • 为带查询字符串的图像添加localPatterns
  • images.domains迁移到images.remotePatterns
  • 按需审查并更新默认值

8. 缓存 API 更新

8.1 移除 unstable_ 前缀
// BEFORE (Next.js 15) import { unstable_cacheLife as cacheLife, unstable_cacheTag as cacheTag, } from 'next/cache'; // AFTER (Next.js 16) import { cacheLife, cacheTag } from 'next/cache';
8.2 新的缓存函数

revalidateTag 配合 cacheLife profile

'use server'; import { revalidateTag } from 'next/cache'; export async function updateArticle(articleId: string) { revalidateTag(`article-${articleId}`, 'max'); }

updateTag(新增)

'use server'; import { updateTag } from 'next/cache'; export async function updateUserProfile(userId: string, profile: Profile) { await db.users.update(userId, profile); updateTag(`user-${userId}`); }

refresh(新增)

'use server'; import { refresh } from 'next/cache'; export async function markNotificationAsRead(notificationId: string) { await db.notifications.markAsRead(notificationId); refresh(); }

操作清单:

  • cacheLifecacheTag的导入中移除unstable_前缀
  • 考虑使用新的updateTagrefresh函数

9. React Compiler 支持

React Compiler 现已稳定并被支持:

// next.config.ts const nextConfig = { reactCompiler: true, }; export default nextConfig;

安装插件:

npm install -D babel-plugin-react-compiler

注意:启用 React Compiler 后编译时间会变长。

10. 滚动行为覆盖(Scroll Behavior Override)

Next.js 不再在导航期间覆盖scroll-behavior: smooth。如需恢复之前的行为:

// app/layout.tsx export default function RootLayout({ children }) { return ( <html lang="en"># Run migration codemod npx @next/codemod@canary next-lint-to-eslint-cli .

next.config.js中移除:

// Remove this { eslint: { } }

操作清单:

  • 运行 ESLint 迁移 codemod
  • next.config.js中移除eslint配置
  • 将 CI 脚本改为直接使用eslint,而不是next lint

12. 特性移除(Feature Removals)

12.1 AMP 支持被移除
  • 所有 AMP API 已被删除
  • 移除useAmphook 用法
  • 移除amp配置项
  • 删除 AMP 专用页面
12.2 运行时配置被移除
// BEFORE - Remove these module.exports = { serverRuntimeConfig: { dbUrl: process.env.DATABASE_URL }, publicRuntimeConfig: { apiUrl: '/api' }, };

服务端配置迁移——直接使用环境变量:

// Use environment variables directly async function fetchData() { const dbUrl = process.env.DATABASE_URL; return await db.query(dbUrl, 'SELECT * FROM users'); }

客户端配置迁移

# .env.local NEXT_PUBLIC_API_URL="/api"
'use client'; export default function Component() { const apiUrl = process.env.NEXT_PUBLIC_API_URL; // ... }
12.3 devIndicators 选项被移除

next.config.js中移除以下选项:

  • appIsrStatus
  • buildActivity
  • buildActivityPosition
12.4 experimental.dynamicIO 重命名
// BEFORE { experimental: { dynamicIO: true; } } // AFTER { cacheComponents: true; }
12.5 unstable_rootParams 被移除

该 API 已删除,请等待未来 minor 版本中的替代 API。

操作清单:

  • 移除所有 AMP 相关代码
  • 将运行时配置迁移到环境变量
  • 移除弃用的 devIndicators 选项
  • dynamicIO重命名为cacheComponents

13. 开发相关变更

13.1 并行 dev 与 build

开发环境现在输出到.next/dev(与 build 输出分离)。更新 Turbopack tracing 命令:

npx next internal trace .next/dev/trace-turbopack

四、迁移后验证(Post-Migration Validation)

1. 逐项目构建

# Build each Next.js project individually nx run PROJECT_NAME:build

2. 启动开发服务器

# Start dev server to verify Turbopack works nx run PROJECT_NAME:serve

3. 构建所有受影响项目

# Build all affected projects nx affected -t build

4. 运行完整验证

# Run full CI validation nx prepush

5. 复查迁移清单

  • 所有异步请求 API 已更新
  • 所有使用 params 的 page/layout 组件已改为 async
  • Turbopack 配置已更新
  • Middleware 已重命名为 proxy
  • 并行路由已有 default.js 文件
  • 图像配置已更新
  • 缓存导入已更新(移除 unstable_ 前缀)
  • AMP 代码已移除
  • 运行时配置已迁移到环境变量
  • ESLint 配置已迁移
  • 所有项目构建成功
  • 开发服务器正常启动

五、常见问题与解决方案

问题解决方案
"cookies() expects to be called in a synchronous context"将函数改为 async 并await cookies()
"params should be awaited before accessing properties"在访问props.params前添加await
使用 Turbopack 时构建失败为 build 脚本添加--webpack标志,然后逐步解决 Turbopack 兼容性
重命名后 Middleware 不生效确保文件和函数都已从middleware重命名为proxy
并行路由不渲染为并行路由插槽添加default.tsx文件
带查询字符串的图像无法加载为这些图像添加localPatterns配置
params 类型相关 TypeScript 报错运行npx next typegen生成类型辅助,并使用PagePropsLayoutProps类型

六、需要审查的文件清单

创建一份所有待审查文件的清单:

# Find all pages with potential params usage find . -path "*/app/*" -name "page.tsx" -o -name "page.ts" | xargs grep -l "params\|searchParams" # Find all layouts find . -path "*/app/*" -name "layout.tsx" -o -name "layout.ts" # Find all route handlers find . -path "*/app/*" -name "route.ts" -o -name "route.tsx" # Find middleware files find . -name "middleware.ts" -o -name "middleware.js" # Find files using cookies/headers rg "from 'next/headers'" --type ts --type tsx # Find next.config files find . -name "next.config.*" -not -path "*/node_modules/*" # Find parallel routes find . -path "*/app/@*" -type d

七、大型工作区的迁移策略

  1. 分阶段迁移:从一个小项目开始,验证通过后再扩大范围
  2. 使用 codemod:运行npx @next/codemod@canary upgrade latest完成自动化修复
  3. 生成类型:运行npx next typegen获得类型安全的迁移
  4. 频繁运行测试:每次配置变更后,运行受影响的测试
  5. 记录问题:跟踪记录项目特定问题及其解决方案

在 Nx 工作区中,还可以利用nx affected系列命令把验证范围精确收敛到受影响的图(project graph)节点上:改完一批文件后执行nx affected -t build,Nx 只会构建受影响的项目及其依赖链,大幅缩短反馈回路。

八、迁移期间的常用命令

# Find all Next.js projects nx show projects --with-target build # Build specific project nx build PROJECT_NAME # Serve specific project nx serve PROJECT_NAME # Build all affected nx affected -t build # View project details nx show project PROJECT_NAME --web # Clear Nx cache if needed nx reset

九、LLM / Agent 执行注意事项(Notes for LLM Execution)

原文档的最后一节专门面向自动化执行者,如果你的迁移由 LLM/Agent 驱动,请严格遵循以下执行纪律:

  1. 系统性推进:完成一个类别后再进入下一个类别,不要跳步
  2. 每次变更后测试:不要积压所有变更后再统一验证
  3. 保持用户知情:在推进每个小节时同步汇报进度
  4. 及时处理错误:构建失败时立即修复,不要带着错误继续
  5. 优先使用 codemod:让@next/codemod处理重复的 async/await 改写
  6. 优先处理破坏性变更:先聚焦异步 API,它影响面最大
  7. 创建有意义的提交:将相关变更分组提交,配以清晰的提交信息
  8. 使用 TodoWrite 工具:通过任务清单跟踪迁移进度,保持可见性

结语

Next.js 16 的这次升级,破坏性变更集中在异步化(Async Request APIs、图像生成、sitemap、缓存函数)、默认打包器切换(Turbopack)、命名重构(Middleware→Proxy、dynamicIO→cacheComponents)与一批功能移除(AMP、runtimeConfig、next lint)上。在 Nx 工作区中,这份由 migrations.json 注册的迁移指令文档既是人工升级的操作手册,也是 Nx Agent 化迁移(packages/nx/src/command-line/migrate/agentic/)的执行蓝本。按照"识别项目 → 更新依赖 → 分类改写 → 逐项目验证 → 全量回归"的路径推进,配合 codemod 与nx affected的增量验证,即可在控制风险的前提下完成整个工作区的升级。

【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 23:14:57

Android车载串口开发实战:UART/RS485通信全链路解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 23:09:03

蒙特卡洛与概率距离:风光场景生成与削减实战方法

我们在做电力系统随机优化或者微电网规划的时候&#xff0c;经常要面对一个很实在的问题&#xff1a;风光出力怎么描述&#xff1f;直接拿一整年时序数据丢进去&#xff0c;计算量吃不消&#xff1b;只取典型日&#xff0c;又怕丢掉极端情况。我自己最早是被一个“要生成500个风…

作者头像 李华
网站建设 2026/9/12 23:06:13

豆包+飞书实现松弛工作:智能提效与协作范式升级

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 23:03:59

大数据产品标准化:核心要素与行业实践

1. 大数据领域数据产品的行业标准概述大数据行业经过十余年发展&#xff0c;已经从单纯的技术探索阶段进入标准化、规范化阶段。数据产品作为大数据价值变现的核心载体&#xff0c;其标准化程度直接影响着行业健康发展。当前主流的数据产品标准体系主要包含三个维度&#xff1a…

作者头像 李华
网站建设 2026/9/12 23:03:28

Flutter依赖注入库qinject的鸿蒙适配实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华