Back返回博客

Next.js 15 发布

Next.js 15 带来了 React 19 支持、缓存优化、开发环境下 Turbopack 的稳定版本发布、新 API 等一系列更新。

Next.js 15 已正式发布稳定版并可用于生产环境。该版本基于 RC1RC2 的更新构建而成。我们在确保稳定性的同时,加入了一些令人兴奋的新特性。立即体验 Next.js 15:

terminal
# 使用全新的自动化升级 CLI
npx @next/codemod@canary upgrade latest
 
# 或手动升级
npm install next@latest react@rc react-dom@rc

我们也很高兴地宣布,更多关于未来发展的内容将在 10 月 24 日(本周四)的 Next.js 大会 上分享。

以下是 Next.js 15 的主要更新:

通过 @next/codemod CLI 实现平滑升级

每个 Next.js 主要版本都包含自动化代码转换工具(codemods)以帮助处理破坏性变更。

为了让升级更加顺畅,我们发布了增强版 codemod CLI:

Terminal
npx @next/codemod@canary upgrade latest

该工具可帮助你将代码库升级至最新稳定版或预发布版本。CLI 将更新依赖项、显示可用 codemods 并指导你完成应用过程。

canary 标签使用最新版 codemod,而 latest 指定 Next.js 版本。我们建议即使升级到最新版 Next.js 也使用 canary 版本的 codemod,因为我们计划根据反馈持续改进该工具。

了解更多关于 Next.js codemod CLI 的信息。

异步请求 API(破坏性变更)

在传统的服务端渲染 (SSR) 中,服务器需要等待请求后才能渲染内容。然而并非所有组件都依赖请求特定数据,因此等待请求来渲染它们是不必要的。理想情况下,服务器应在请求到达前完成尽可能多的准备工作。为了实现这一点并为未来优化奠定基础,我们需要明确何时需要等待请求。

因此,我们将依赖请求特定数据的 API —— 如 headerscookiesparamssearchParams —— 改为异步实现。

import { cookies } from 'next/headers';
 
export async function AdminPanel() {
  const cookieStore = await cookies();
  const token = cookieStore.get('token');
 
  // ...
}

这是破坏性变更,影响以下 API:

  • cookies
  • headers
  • draftMode
  • layout.jspage.jsroute.jsdefault.jsgenerateMetadatagenerateViewport 中的 params
  • page.js 中的 searchParams

为便于迁移,这些 API 暂时仍可通过同步方式访问,但会在开发和生产环境中显示警告,直到下一个主要版本。我们提供了 codemod 来自动化迁移:

Terminal
npx @next/codemod@canary next-async-request-api .

若 codemod 无法完全迁移你的代码,请阅读 升级指南。我们还提供了 示例 展示如何将 Next.js 应用迁移至新 API。

缓存语义

Next.js 应用路由最初采用了预设的缓存默认值,旨在默认提供最高性能选项,同时允许在需要时选择退出。

根据社区反馈,我们重新评估了 缓存启发式规则 及其与部分预渲染 (PPR) 项目和使用 fetch 的第三方库的交互方式。

在 Next.js 15 中,我们将 GET 路由处理器和客户端路由缓存的默认行为从"默认缓存"改为"默认不缓存"。如需保留先前行为,仍可选择启用缓存。

我们将在未来几个月继续改进 Next.js 的缓存机制,并很快分享更多细节。

GET 路由处理器默认不再缓存

在 Next.js 14 中,使用 GET HTTP 方法的路由处理器默认会被缓存,除非它们使用了动态函数或动态配置选项。在 Next.js 15 中,GET 函数默认不缓存

你仍可通过静态路由配置选项如 export dynamic = 'force-static' 选择启用缓存。

特殊路由处理器如 sitemap.tsopengraph-image.tsxicon.tsx 及其他 元数据文件 默认保持静态,除非使用动态函数或动态配置选项。

客户端路由缓存默认不再缓存页面组件

在 Next.js 14.2.0 中,我们引入了实验性 staleTimes 标志以支持自定义配置 路由缓存

在 Next.js 15 中,该标志仍然可用,但我们已将页面片段的默认 staleTime 改为 0。这意味着当你在应用中导航时,客户端将始终反映来自激活页面组件的最新数据。但以下重要行为保持不变:

  • 共享布局数据不会从服务器重新获取,以继续支持 部分渲染
  • 前进/后退导航仍会从缓存恢复以确保浏览器能保持滚动位置
  • loading.js 仍会缓存 5 分钟(或 staleTimes.static 配置的值)

可通过以下配置选择启用先前的客户端路由缓存行为:

next.config.ts
const nextConfig = {
  experimental: {
    staleTimes: {
      dynamic: 30,
    },
  },
};
 
export default nextConfig;

React 19 支持

作为 Next.js 15 发布的一部分,我们决定与即将发布的 React 19 保持同步。

在版本 15 中,应用路由使用 React 19 RC,同时根据社区反馈,我们也为页面路由提供了 React 18 的向后兼容支持。如果你使用页面路由,这允许你在准备就绪时升级到 React 19。

尽管 React 19 仍处于 RC 阶段,但我们在真实应用中的广泛测试以及与 React 团队的紧密合作使我们对其稳定性充满信心。核心破坏性变更已得到充分测试,不会影响现有的应用路由用户。因此,我们决定现在发布稳定的 Next.js 15,让你的项目为 React 19 正式版做好充分准备。

为确保过渡尽可能顺利,我们提供了 codemods 和自动化工具 来协助迁移过程。

阅读 Next.js 15 升级指南React 19 升级指南,并观看 React 大会主题演讲 了解更多。

页面路由支持 React 18

Next.js 15 为页面路由保持了 React 18 的向后兼容性,允许用户在继续使用 React 18 的同时享受 Next.js 15 的改进。

自第一个候选版本 (RC1) 以来,根据社区反馈,我们将重点转向包含对 React 18 的支持。这种灵活性使你能在使用页面路由和 React 18 的同时采用 Next.js 15,从而更好地控制升级路径。

注意: 虽然可以在同一应用中同时运行基于 React 18 的页面路由和基于 React 19 的应用路由,但我们不建议这种配置。这可能导致不可预测的行为和类型不一致,因为两个版本间的底层 API 和渲染逻辑可能不完全一致。

React 编译器(实验性)

React 编译器 是 Meta 的 React 团队创建的新实验性编译器。该编译器通过其对纯 JavaScript 语义和 React 规则 的深入理解,能够为你的代码添加自动优化。编译器减少了开发者需要手动进行的记忆化操作(如使用 useMemouseCallback API),使代码更简洁、更易维护且更少出错。

Next.js 15 新增了对 React 编译器 的支持。了解更多关于 React 编译器及 可用的 Next.js 配置选项 的信息。

注意: React 编译器目前仅作为 Babel 插件提供,这会导致开发和构建时间变慢。

水合错误改进

Next.js 14.1 对错误信息和水合错误进行了改进。Next.js 15 在此基础上进一步优化,提供了增强版的水合错误视图。现在水合错误会显示错误源代码,并给出修复建议。

例如,这是 Next.js 14.1 之前的水合错误提示:

Next.js 14.1 的水合错误提示

Next.js 15 已将其改进为:

Next.js 15 改进后的水合错误提示

Turbopack 开发模式

我们很高兴地宣布,next dev --turbo 现已稳定可用,将显著提升您的开发体验。我们已在 vercel.comnextjs.orgv0 等所有应用中使用该功能,效果显著。

以大型 Next.js 应用 vercel.com 为例,我们观察到:

  • 本地服务启动速度最高提升 76.7%
  • Fast Refresh 代码更新速度最高提升 96.3%
  • 无缓存情况下的初始路由编译速度最高提升 45.8%(Turbopack 暂不支持磁盘缓存)

您可以通过我们的新博客文章了解更多关于 Turbopack 开发模式的信息。

静态路由标识

Next.js 现在会在开发时显示静态路由标识,帮助您区分静态路由与动态路由。这一视觉提示让您更容易通过理解页面渲染方式来优化性能。

您也可以通过 next build 输出查看所有路由的渲染策略。

此更新是我们持续增强 Next.js 可观测性的一部分,旨在帮助开发者更轻松地监控、调试和优化应用。我们还在开发专属开发者工具,更多细节即将公布。

了解更多关于静态路由标识的信息,该功能支持关闭。

使用 unstable_after 在响应后执行代码(实验性)

处理用户请求时,服务器通常执行与计算响应直接相关的任务。但您可能还需要执行日志记录、分析和其他外部系统同步等任务。

由于这些任务与响应无直接关联,用户无需等待其完成。将这些工作推迟到响应后执行存在挑战,因为无服务器函数会在响应结束后立即停止计算。

after() 是一个新的实验性 API,通过允许您在响应流结束后调度任务来解决此问题,使得次要任务能在不阻塞主要响应的情况下运行。

启用方式是在 next.config.js 中添加 experimental.after

next.config.ts
const nextConfig = {
  experimental: {
    after: true,
  },
};
 
export default nextConfig;

然后在服务端组件、服务端操作、路由处理器或中间件中导入该函数。

import { unstable_after as after } from 'next/server';
import { log } from '@/app/utils';
 
export default function Layout({ children }) {
  // 次要任务
  after(() => {
    log();
  });
 
  // 主要任务
  return <>{children}</>;
}

了解更多关于 unstable_after 的信息。

instrumentation.js(稳定版)

通过 register() API,instrumentation 文件允许用户接入 Next.js 服务端生命周期,用于监控性能、追踪错误来源,并与 OpenTelemetry 等可观测性工具深度集成。

该功能现已稳定,可以移除 experimental.instrumentationHook 配置项。

此外,我们与 Sentry 合作设计了新的 onRequestError 钩子,可用于:

  • 捕获服务端所有错误的关键上下文,包括:
    • 路由:页面路由或应用路由
    • 服务端上下文:服务端组件、服务端操作、路由处理器或中间件
  • 将错误报告给您喜欢的可观测性提供商
export async function onRequestError(err, request, context) {
  await fetch('https://...', {
    method: 'POST',
    body: JSON.stringify({ message: err.message, request, context }),
    headers: { 'Content-Type': 'application/json' },
  });
}
 
export async function register() {
  // 初始化您喜欢的可观测性提供商 SDK
}

了解更多关于 onRequestError 函数的信息。

<Form> 组件

新的 <Form> 组件扩展了 HTML <form> 元素,支持预加载客户端导航和渐进增强。

适用于需要导航到新页面的表单,例如跳转到结果页的搜索表单。

app/page.jsx
import Form from 'next/form';
 
export default function Page() {
  return (
    <Form action="/search">
      <input name="query" />
      <button type="submit">提交</button>
    </Form>
  );
}

<Form> 组件提供以下功能:

  • 预加载:当表单在视图中时,预加载布局加载 UI,使导航更快
  • 客户端导航:提交时保留共享布局和客户端状态
  • 渐进增强:即使 JavaScript 未加载,表单仍可通过整页导航工作

以往实现这些功能需要大量样板代码。例如:

// 注意:此为演示简化版,不建议在生产代码中使用
 
'use client'
 
import { useEffect } from 'react'
import { useRouter } from 'next/navigation'
 
export default function Form(props) {
  const action = props.action
  const router = useRouter()
 
  useEffect(() => {
    // 如果表单目标是 URL 则预加载
    if (typeof action === 'string') {
      router.prefetch(action)
    }
  }, [action, router])
 
  function onSubmit(event) {
    event.preventDefault()
 
    // 收集所有表单字段并触发带编码数据的 router.push
    const formData = new FormData(event.currentTarget)
    const data = new URLSearchParams()
 
    for (const [name, value] of formData) {
      data.append(name, value as string)
    }
 
    router.push(`${action}?${data.toString()}`)
  }
 
  if (typeof action === 'string') {
    return <form onSubmit={onSubmit} {...props} />
  }
 
  return <form {...props} />
}

了解更多关于 <Form> 组件的信息。

支持 next.config.ts

Next.js 现在支持 TypeScript 格式的 next.config.ts 文件,并提供 NextConfig 类型以实现自动补全和类型安全:

next.config.ts
import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  /* 配置项写在这里 */
};
 
export default nextConfig;

了解更多关于 Next.js 的 TypeScript 支持

自托管改进

自托管应用时,您可能需要更多控制 Cache-Control 指令。

一个常见场景是控制 ISR 页面的 stale-while-revalidate 周期。我们实现了两项改进:

  1. 现在可以在 next.config 中配置 expireTime 值(原为 experimental.swrDelta 选项)
  2. 将默认值更新为一年,确保大多数 CDN 能完全按预期应用 stale-while-revalidate 语义

我们也不再使用默认值覆盖自定义的 Cache-Control 值,允许完全控制并确保与任何 CDN 设置兼容。

最后,我们改进了自托管时的图片优化。之前建议手动安装 sharp 来优化 Next.js 服务器上的图片,但这一建议有时会被忽略。Next.js 15 中,使用 next start独立输出模式运行时,无需手动安装 sharp——Next.js 会自动使用。

了解更多,请查看我们关于自托管 Next.js 的新演示和教程视频

服务端操作安全性增强

服务端操作是可从客户端调用的服务端函数,通过在文件顶部添加 'use server' 指令并导出异步函数来定义。

即使服务端操作或工具函数未在代码中导入,它仍是公开可访问的 HTTP 端点。虽然这种行为在技术上是正确的,但可能导致这些函数被无意暴露。

为增强安全性,我们引入了以下改进:

  • 死代码消除:未使用的服务端操作不会将其 ID 暴露给客户端 JavaScript 包,减小包体积并提升性能
  • 安全操作 ID:Next.js 现在会创建不可预测的非确定性 ID,允许客户端引用和调用服务端操作。这些 ID 会在构建间定期重新计算以增强安全性
// app/actions.js
'use server';
 
// 此操作在应用中使用,Next.js 会创建安全 ID
// 允许客户端引用和调用该服务端操作
export async function updateUserAction(formData) {}
 
// 此操作未在应用中使用,Next.js 会在 `next build` 时
// 自动移除该代码,且不会创建公共端点
export async function deleteUserAction(formData) {}

您仍应将服务端操作视为公共 HTTP 端点。了解更多关于保护服务端操作的信息。

优化外部包打包(稳定版)

打包外部包可以提升应用的冷启动性能。在应用路由中,外部包默认会打包,您可以使用新的 serverExternalPackages 配置项选择排除特定包。

页面路由中,外部包默认不打包,但您可以使用现有的 transpilePackages 选项指定要打包的包列表。使用此配置项需要逐个指定包。

为统一应用路由和页面路由的配置,我们引入了新选项 bundlePagesRouterDependencies 来匹配应用路由的默认自动打包行为。然后您可以根据需要使用 serverExternalPackages 排除特定包。

next.config.ts
const nextConfig = {
  // 在页面路由中自动打包外部包:
  bundlePagesRouterDependencies: true,
  // 为应用路由和页面路由排除特定包:
  serverExternalPackages: ['package-name'],
};
 
export default nextConfig;

了解更多关于优化外部包的信息。

ESLint 9 支持

Next.js 15 还引入了对 ESLint 9 的支持,ESLint 8 将于 2024 年 10 月 5 日终止支持。

为确保平稳过渡,Next.js 保持向后兼容,意味着您可以继续使用 ESLint 8 或 9。

如果您升级到 ESLint 9 且我们检测到您尚未采用新配置格式,Next.js 会自动应用 ESLINT_USE_FLAT_CONFIG=false 逃生舱以简化迁移。

此外,运行 next lint 时将移除已弃用的选项如 —ext—ignore-path。请注意 ESLint 最终将在 ESLint 10 中禁用这些旧配置,因此建议尽快开始迁移。

有关这些变更的更多详情,请查看迁移指南

作为本次更新的一部分,我们还升级了 eslint-plugin-react-hooksv5.0.0,引入了 React Hooks 使用的新规则。您可以在 [email protected] 的变更日志 中查看所有变更。

开发与构建改进

服务端组件热更新

开发过程中,保存服务端组件时会重新执行它们。这意味着对 API 端点或第三方服务的任何 fetch 请求也会被调用。

为提升本地开发性能并减少计费 API 调用的潜在成本,我们现在确保热模块替换 (HMR) 可以复用之前渲染的 fetch 响应。

了解更多关于服务端组件 HMR 缓存的信息。

App Router 的静态生成优化

我们优化了静态生成过程以提升构建速度,特别是针对含有慢速网络请求的页面。

此前,我们的静态优化流程会对页面进行两次渲染——第一次生成客户端导航所需数据,第二次渲染初始访问的 HTML。现在,我们复用首次渲染结果,省去第二次渲染环节,从而减少工作量并缩短构建时间。

此外,静态生成工作线程现在会在多个页面间共享 fetch 缓存。如果 fetch 调用未显式禁用缓存,其返回结果将被同一工作线程处理的其他页面复用,这有效减少了重复数据的请求次数。

高级静态生成控制(实验性功能)

我们新增了实验性功能,为需要精细控制的特殊场景提供更灵活的静态生成流程管理。

除非有特定需求,否则建议保持当前默认配置,因为这些选项可能因并发量增加导致资源消耗上升,甚至引发内存不足错误。

next.config.ts
const nextConfig = {
  experimental: {
    // Next.js 在构建失败前会重试失败的页面生成次数
    staticGenerationRetryCount: 1
    // 每个工作线程处理的最大页面数
    staticGenerationMaxConcurrency: 8
    // 启动新导出工作线程前的最小页面数阈值
    staticGenerationMinPagesPerWorker: 25
  },
}
 
export default nextConfig;

了解更多关于静态生成选项的信息。

其他变更

  • [重大变更] next/image:移除 squoosh 依赖,改用可选依赖 sharp (PR)
  • [重大变更] next/image:默认 Content-Disposition 改为 attachment (PR)
  • [重大变更] next/image:src 含首尾空格时将报错 (PR)
  • [重大变更] 中间件:应用 react-server 条件限制不推荐的 React API 导入 (PR)
  • [重大变更] next/font:移除对外部 @next/font 包的支持 (PR)
  • [重大变更] next/font:移除 font-family 哈希处理 (PR)
  • [重大变更] 缓存:force-dynamic 现在会为 fetch 缓存设置 no-store 默认值 (PR)
  • [重大变更] 配置:默认启用 swcMinify (PR)、missingSuspenseWithCSRBailout (PR) 和 outputFileTracing (PR) 并移除废弃选项
  • [重大变更] 移除 Speed Insights 的自动检测(需改用专用包 @vercel/speed-insights)(PR)
  • [重大变更] 移除动态站点地图路由的 .xml 扩展名,统一开发与生产环境下的站点地图 URL (PR)
  • [重大变更] 我们已弃用在 App Router 中使用 export const runtime = "experimental-edge",现在应切换至 export const runtime = "edge"。我们提供了 代码迁移工具 来执行此操作 (PR)
  • [重大变更] 在渲染过程中调用 revalidateTagrevalidatePath 现在会抛出错误 (PR)
  • [重大变更] instrumentation.jsmiddleware.js 文件现在将使用内置的 React 包 (PR)
  • [重大变更] 最低 Node.js 版本要求已更新至 18.18.0 (PR)
  • [重大变更] next/dynamic:已移除废弃的 suspense 属性,在 App Router 中使用时将不再插入空的 Suspense 边界 (PR)
  • [重大变更] 在 Edge Runtime 解析模块时,不再应用 worker 模块条件 (PR)
  • [重大变更] 禁止在服务端组件中将 ssr: false 选项与 next/dynamic 一起使用 (PR)
  • [改进] 元数据:更新了 Vercel 托管环境下 metadataBase 的环境变量回退逻辑 (PR)
  • [改进] 修复了 optimizePackageImports 中混合命名空间与命名导入时的 Tree Shaking 问题 (PR)
  • [改进] 并行路由:为未匹配的 catch-all 路由提供所有已知参数 (PR)
  • [改进] 配置项 bundlePagesExternals 已稳定并更名为 bundlePagesRouterDependencies
  • [改进] 配置项 serverComponentsExternalPackages 已稳定并更名为 serverExternalPackages
  • [改进] create-next-app:新项目默认忽略所有 .env 文件 (PR)
  • [改进] outputFileTracingRootoutputFileTracingIncludesoutputFileTracingExcludes 已结束实验状态转为稳定功能 (PR)
  • [改进] 避免将全局 CSS 文件与深层树结构中的 CSS 模块文件合并 (PR)
  • [改进] 现在可通过 NEXT_CACHE_HANDLER_PATH 环境变量指定缓存处理器 (PR)
  • [改进] Pages Router 现在同时支持 React 18 和 React 19 (PR)
  • [改进] 当启用检查器时,错误覆盖层现在会显示复制 Node.js 检查器 URL 的按钮 (PR)
  • [改进] App Router 中的客户端预取现在使用 priority 属性 (PR)
  • [改进] Next.js 现在提供 unstable_rethrow 函数用于在 App Router 中重新抛出内部错误 (PR)
  • [改进] unstable_after 现在可用于静态页面 (PR)
  • [改进] 如果在 SSR 期间使用 next/dynamic 组件,将预加载对应 chunk (PR)
  • [改进] App Router 现在支持 esmExternals 选项 (PR)
  • [改进] 新增 experimental.allowDevelopmentBuild 选项允许在调试时使用 NODE_ENV=development 执行 next build (PR)
  • [改进] 在 Pages Router 中禁用服务端动作转换 (PR)
  • [改进] 构建工作线程现在会在退出时防止构建过程挂起 (PR)
  • [改进] 从服务端动作重定向时,重新验证现在会正确应用 (PR)
  • [改进] Edge Runtime 现在能正确处理并行路由的动态参数 (PR)
  • [改进] 静态页面现在会在初始加载后遵守 staleTime 设置 (PR)
  • [改进] 更新 vercel/og 修复内存泄漏问题 (PR)
  • [改进] 调整时间补丁以支持 msw 等 API 模拟工具的使用 (PR)
  • [改进] 预渲染页面应使用静态 staleTime (PR)

了解更多信息,请查看升级指南

贡献者

Next.js 是 3000 多位独立开发者、Google 和 Meta 等行业合作伙伴以及 Vercel 核心团队共同努力的成果。本版本由以下成员共同打造:

特别感谢 @AbhiShake1、@Aerilym、@AhmedBaset 等所有贡献者(完整名单见原文)的鼎力相助!