ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

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

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/nxNext.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.jsonnext升级到~16.0.1、eslint-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 Checklist1. 识别所有 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 nextlatest reactlatest react-domlatest npm install -D types/react types/react-dom # if using TypeScript3. 核验最低环境要求Node.js 20.9Node.js 18 不再受支持TypeScript 5.1.0浏览器支持Chrome 111、Edge 111、Firefox 111、Safari 16.4三、按类别的迁移步骤1. 异步请求 APIAsync Request APIs最大破坏性变更这是 Next.js 16 影响面最大的变更所有动态请求 API 都变为异步。需要重点检索的模式服务端组件中的cookies()用法服务端组件中的headers()用法draftMode()用法page、layout、route handler 和 metadata 文件中的paramspage 组件中的searchParams1.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前添加await1.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/codemodcanary upgrade latest生成类型辅助工具以获得更安全的迁移Next.js 15.5npx next typegen这会生成PageProps、LayoutProps和RouteContext类型辅助。它也是后续解决 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对params和id的访问都添加await3. 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.ts或middleware.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?v1 altPhoto width100 height100 /// next.config.js module.exports { images: { localPatterns: [ { pathname: /assets/**, search: ?v1, }, ], }, };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 profileuse 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(); }操作清单从cacheLife和cacheTag的导入中移除unstable_前缀考虑使用新的updateTag和refresh函数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 OverrideNext.js 不再在导航期间覆盖scroll-behavior: smooth。如需恢复之前的行为// app/layout.tsx export default function RootLayout({ children }) { return ( html langen># Run migration codemod npx next/codemodcanary next-lint-to-eslint-cli .从next.config.js中移除// Remove this { eslint: { } }操作清单运行 ESLint 迁移 codemod从next.config.js中移除eslint配置将 CI 脚本改为直接使用eslint而不是next lint12. 特性移除Feature Removals12.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/apiuse client; export default function Component() { const apiUrl process.env.NEXT_PUBLIC_API_URL; // ... }12.3 devIndicators 选项被移除从next.config.js中移除以下选项appIsrStatusbuildActivitybuildActivityPosition12.4 experimental.dynamicIO 重命名// BEFORE { experimental: { dynamicIO: true; } } // AFTER { cacheComponents: true; }12.5 unstable_rootParams 被移除该 API 已删除请等待未来 minor 版本中的替代 API。操作清单移除所有 AMP 相关代码将运行时配置迁移到环境变量移除弃用的 devIndicators 选项将dynamicIO重命名为cacheComponents13. 开发相关变更13.1 并行 dev 与 build开发环境现在输出到.next/dev与 build 输出分离。更新 Turbopack tracing 命令npx next internal trace .next/dev/trace-turbopack四、迁移后验证Post-Migration Validation1. 逐项目构建# Build each Next.js project individually nx run PROJECT_NAME:build2. 启动开发服务器# Start dev server to verify Turbopack works nx run PROJECT_NAME:serve3. 构建所有受影响项目# Build all affected projects nx affected -t build4. 运行完整验证# Run full CI validation nx prepush5. 复查迁移清单所有异步请求 API 已更新所有使用 params 的 page/layout 组件已改为 asyncTurbopack 配置已更新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生成类型辅助并使用PageProps、LayoutProps类型六、需要审查的文件清单创建一份所有待审查文件的清单# 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七、大型工作区的迁移策略分阶段迁移从一个小项目开始验证通过后再扩大范围使用 codemod运行npx next/codemodcanary upgrade latest完成自动化修复生成类型运行npx next typegen获得类型安全的迁移频繁运行测试每次配置变更后运行受影响的测试记录问题跟踪记录项目特定问题及其解决方案在 Nx 工作区中还可以利用nx affected系列命令把验证范围精确收敛到受影响的图project graph节点上改完一批文件后执行nx affected -t buildNx 只会构建受影响的项目及其依赖链大幅缩短反馈回路。八、迁移期间的常用命令# 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 驱动请严格遵循以下执行纪律系统性推进完成一个类别后再进入下一个类别不要跳步每次变更后测试不要积压所有变更后再统一验证保持用户知情在推进每个小节时同步汇报进度及时处理错误构建失败时立即修复不要带着错误继续优先使用 codemod让next/codemod处理重复的 async/await 改写优先处理破坏性变更先聚焦异步 API它影响面最大创建有意义的提交将相关变更分组提交配以清晰的提交信息使用 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),仅供参考
返回列表