跳到内容
返回博客

2024 年 10 月 15 日,星期二

Next.js 15 RC 2

发布者

继五月份发布首个 Next.js 15 Release Candidate 公告 之后,我们一直在根据您的反馈准备第二个 Release Candidate。以下是我们一直在做的工作

立即试用 Next.js 15 Release Candidate (RC2)

# Use the new automated upgrade CLI
npx @next/codemod@canary upgrade rc
 
# ...or upgrade manually
npm install next@rc react@rc react-dom@rc

注意: 此 Release Candidate 包含来自之前的 RC的所有更改。

使用 codemod CLI 实现平滑升级

我们在每个 Next.js 主要版本中都包含 codemod(自动代码转换),以帮助自动升级重大更改。

为了使升级更加顺畅,我们发布了增强的 codemod CLI

npx @next/codemod@canary upgrade rc

此工具可帮助您将代码库升级到最新的稳定版或预发布版本。CLI 将更新您的依赖项,显示可用的 codemod,并指导您应用它们。命令行上指定的 dist 标签(@rc@canary 等)决定了要升级到的版本。

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

用于开发的 Turbopack

用于本地开发的 Turbopack 将在 Next.js 15 的正式版本中变为稳定版,同时保持可选。您可以通过运行以下命令立即试用它

next dev --turbo

感谢成千上万的开发者参与测试、报告问题并验证 Turbopack Beta 和 Release Candidate 阶段的修复,我们解决了自第一个 Next.js 15 Release Candidate 以来的 54 个 GitHub 问题。除了社区的努力之外,我们在 vercel.comv0.devnextjs.org 上的内部测试也帮助确定了许多额外的改进。

在过去的三个月中,我们专注于优化冷编译性能。与之前的版本相比,我们看到了

  • 内存使用量减少 25–35%
  • 对于具有数千个模块的大型页面,编译速度加快 30–50%

我们将在未来的版本中继续优化这些领域。

展望未来,Turbopack 团队在持久缓存、内存使用量减少以及用于 next build 的 Turbopack 方面取得了重大进展——96% 的测试通过

注意: 请参阅 Turbopack 的所有支持和不支持的功能

异步请求 API(重大变更)

在传统的服务器端渲染中,服务器在渲染任何内容之前都会等待请求。但是,并非所有组件都依赖于特定于请求的数据,因此无需等待请求来渲染它们。理想情况下,服务器会在请求到达之前尽可能多地准备。为了实现这一点,并为未来的优化奠定基础,我们需要知道何时等待请求。

因此,我们正在将依赖于特定于请求的数据(例如 headerscookiesparamssearchParams)的 API 转换为异步

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可用于自动化迁移

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

对于 codemod 无法完全迁移您的代码的情况,请阅读升级指南。我们还提供了一个关于如何将 Next.js 应用程序迁移到新 API 的示例

增强服务器操作的安全性

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

即使服务器操作或实用程序函数未在代码的其他位置导入,它仍然是可公开访问的 HTTP 端点。虽然这种行为在技术上是正确的,但它可能会导致意外暴露此类函数。

为了提高安全性,我们引入了以下增强功能

  • 死代码消除: 未使用的服务器操作不会将其 ID 暴露给客户端 JavaScript 包,从而减小包大小并提高性能。
  • 安全操作 ID: Next.js 现在创建不可猜测的、非确定性的 ID,以允许客户端引用和调用服务器操作。这些 ID 会在构建之间定期重新计算,以增强安全性。
// app/actions.js
'use server';
 
// This action **is** used in our application, so Next.js
// will create a secure ID to allow the client to reference
// and call the Server Action.
export async function updateUserAction(formData) {}
 
// This action **is not** used in our application, so Next.js
// will automatically remove this code during `next build`
// and will not create a public endpoint.
export async function deleteUserAction(formData) {}

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

静态路由指示器

Next.js 现在在开发期间显示静态路由指示器,以帮助您识别哪些路由是静态的或动态的。这种可视化提示使您更容易通过了解页面的渲染方式来优化性能。

您还可以使用next build 输出查看所有路由的渲染策略。

此更新是我们不断努力增强 Next.js 可观测性的一部分,使开发人员更容易监控、调试和优化其应用程序。我们还在开发专用开发人员工具,更多详细信息即将推出。

了解有关静态路由指示器的更多信息,该指示器可以禁用。

<Form> 组件

新的 <Form> 组件使用预取客户端导航和渐进增强功能扩展了 HTML <form> 元素。

它适用于导航到新页面的表单,例如导致结果页面的搜索表单。

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

<Form> 组件具有以下功能

  • 预取:当表单在视图中时,将预取布局加载 UI,从而加快导航速度。
  • 客户端导航: 提交时,共享布局和客户端状态将保留。
  • 渐进增强:如果 JavaScript 尚未加载,表单仍然可以通过完整页面导航工作。

以前,实现这些功能需要大量手动样板代码。例如

示例
// Note: This is abbreviated for demonstration purposes.
// Not recommended for use in production code.
 
'use client'
 
import { useEffect } from 'react'
import { useRouter } from 'next/navigation'
 
export default function Form(props) {
  const action = props.action
  const router = useRouter()
 
  useEffect(() => {
    // if form target is a URL, prefetch it
    if (typeof action === 'string') {
      router.prefetch(action)
    }
  }, [action, router])
 
  function onSubmit(event) {
    event.preventDefault()
 
    // grab all of the form fields and trigger a `router.push` with the data URL encoded
    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 类型

import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  /* config options here */
};
 
export default nextConfig;

了解有关 Next.js 中TypeScript 支持的更多信息。

instrumentation.js(稳定版)

具有 register() API 的 instrumentation 文件允许用户利用 Next.js 服务器生命周期来监控性能、跟踪错误来源并与 OpenTelemetry 等可观测性库深度集成。

此功能现在稳定,可以删除 experimental.instrumentationHook 配置选项。

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

  • 捕获有关服务器上抛出的所有错误的重要上下文,包括
    • 路由器:Pages Router 或 App Router
    • 服务器上下文:服务器组件、服务器操作、路由处理程序或中间件
  • 将错误报告给您喜欢的可观测性提供商。
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() {
  // init your favorite observability provider SDK
}

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

开发和构建改进

服务器组件 HMR

在开发期间,服务器组件在保存时会重新执行。这意味着,对您的 API 端点或第三方服务的任何 fetch 请求也会被调用。

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

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

App Router 的更快静态生成

我们优化了静态生成以提高构建时间,特别是对于具有慢速网络请求的页面。

以前,我们的静态优化过程会渲染页面两次——一次生成客户端导航的数据,第二次渲染初始页面访问的 HTML。现在,我们重用第一次渲染,减少了第二次传递,从而减少了工作负载和构建时间。

此外,静态生成工作进程现在跨页面共享 fetch 缓存。如果 fetch 调用未选择退出缓存,则同一工作进程处理的其他页面将重用其结果。这减少了对相同数据的请求次数。

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

我们为更精细地控制静态生成过程添加了实验性支持,以用于希望从更精细的控制中获益的高级用例。

我们建议坚持当前默认值,除非您有特定要求,因为这些选项可能会因并发性增加而导致资源使用量增加和潜在的内存不足错误。

const nextConfig = {
  experimental: {
	  // how many times Next.js will retry failed page generation attempts
	  // before failing the build
    staticGenerationRetryCount: 1
    // how many pages will be processed per worker
    staticGenerationMaxConcurrency: 8
    // the minimum number of pages before spinning up a new export worker
    staticGenerationMinPagesPerWorker: 25
  },
}
 
export default nextConfig;

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

自托管的改进

在自托管应用程序时,您可能需要更好地控制 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,您不再需要手动安装 sharp — 当使用 next start 或使用独立输出模式运行时,Next.js 将自动使用 sharp

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

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-hooks 升级到了 v5.0.0,其中引入了 React Hooks 使用的新规则。您可以在eslint-plugin-react-hooks@5.0.0 的更改日志中查看所有更改。

其他更改

  • RC 1 博客文章中先前描述的所有更改
  • [重大变更] 我们已弃用在 App Router 中导出 export const runtime = "experimental-edge"。用户现在应该切换到 export const runtime = "edge"。我们添加了一个 codemod 来执行此操作 (PR)
  • [重大变更] 在渲染期间调用 revalidateTagrevalidatePath 现在将抛出错误 (PR)
  • [重大变更] instrumentation.jsmiddleware.js 文件现在将使用 vendored React 包 (PR)
  • [重大变更] 最低要求的 Node.js 版本已更新为 18.18.0 (PR)
  • [重大变更] next/dynamic:已删除已弃用的 suspense prop,并且当组件在 App Router 中使用时,它将不再插入空的 Suspense 边界 (PR)
  • [重大变更] 在 Edge Runtime 上解析模块时,将不会应用 worker 模块条件 (PR)
  • [重大变更] 禁止在服务器组件中的 next/dynamic 中使用 ssr: false 选项 (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 中重新抛出 Next.js 内部错误 (PR)
  • [改进] unstable_after 现在可以在静态页面中使用 (PR)
  • [改进] 如果在 SSR 期间使用 next/dynamic 组件,则将预取 chunk (PR)
  • [改进] App Router 现在支持 esmExternals 选项 (PR)
  • [改进] experimental.allowDevelopmentBuild 选项可用于允许 NODE_ENV=developmentnext build 一起用于调试目的 (PR)
  • [改进] 服务器操作转换现在在 Pages Router 中禁用 (PR)
  • [改进] 构建 workers 现在将在退出时停止构建挂起 (PR)
  • [改进] 从服务器操作重定向时,重新验证现在将正确应用 (PR)
  • [改进] 动态参数现在在 Edge Runtime 上为并行路由正确处理 (PR)
  • [改进] 静态页面现在将在初始加载后遵守 staleTime (PR)
  • [改进] vercel/og 已更新,修复了内存泄漏问题 (PR)
  • [改进] 更新了补丁时序,以允许使用诸如 msw 之类的包进行 API 模拟 (PR)

贡献者

Next.js 是超过 3,000 位个人开发者以及我们在 Vercel 的核心团队共同努力的成果。此版本由以下人员为您带来:

非常感谢 @huozhi, @shuding, @wyattjoh, @PaulAsjes, @mcnaveen, @timneutkens, @stipsan, @aktoriukas, @sirTangale, @greatvivek11, @sokra, @anatoliik-lyft, @wbinnssmith, @coltonehrman, @hungdoansy, @kxlow, @ztanner, @manovotny, @leerob, @ryota-murakami, @ijjk, @pnutmath, @feugy, @Jeffrey-Zutt, @wiesson, @eps1lon, @devjiwonchoi, @Ethan-Arrowood, @kenji-webdev, @domdomegg, @samcx, @Jaaneek, @evanwinter, @kdy1, @balazsorban44, @feedthejim, @ForsakenHarmony, @kwonoj, @delbaoliveira, @xiaohanyu, @dvoytenko, @bobaaaaa, @bgw, @gaspar09, @souporserious, @unflxw, @kiner-tang, @Ehren12, @EffectDoplera, @IAmKushagraSharma, @Auxdible, @sean-rallycry, @jeanmax1me, @unstubbable, @NilsJacobsen, @adiguno, @ryan-nauman, @zsh77, @KagamiChan, @steveluscher, @MehfoozurRehman, @vkryachko, @chentsulin, @samijaber, @begalinsaf, @FluxCapacitor2, @lukahartwig, @brianshano, @pavelglac, @styfle, @symant233, @HristovCodes, @karlhorky, @jonluca, @jonathan-ingram, @mknichel, @sopranopillow, @Gomah, @imddc, @notrab, @gabrielrolfsen, @remorses, @AbhiShake1, @agadzik, @rishabhpoddar, @rezamauliadi, @IncognitoTGT, @webtinax, @BunsDev, @nisabmohd, @z0n, @bennettdams, @joeshub, @n1ckoates, @srkirkland, @RiskyMH, @coopbri, @okoyecharles, @diogocapela, @dnhn, @typeofweb, @davidsa03, @imranolas, @lubieowoce, @maxhaomh, @mirasayon, @blvdmitry, @hwangstar156, @lforst, @emmerich, @christian-bromann, @Lsnsh, @datner, @hiro0218, @flybayer, @ianmacartney, @ypessoa, @ryohidaka, @icyJoseph, @Arinji2, @lovell, @nsams, @Nayeem-XTREME, @JamBalaya56562, @Arindam200, @gaojude, @qqww08, @todor0v, @tokkiyaa, @arlyon, @lorensr, @Juneezee, @Sayakie, @IGassmann, @bosconian-dynamics, @phryneas, @akazwz, @atik-persei, @shubh73, @alpedia0, @chogyejin, @notomo, @ArnoldVanN, @dhruv-kaushik, @kevva, @Kahitar, @anay-208, @boris-szl, @devnyxie, @LorisSigrist, @M-YasirGhaffar, @Lada496, @kippmr, @torresgol10, @pkiv, @Netail, @jontewks, @ArnaudFavier, @chrisjstott, @mratlamwala, @mayank1513, @karlkeefer, @kshehadeh, @Marukome0743, @a89529294, @anku255, @KeisukeNagakawa, @andrii-bodnar, @aldosch, @versecafe, @steadily-worked, @cfrank, @QiuranHu, @farsabbutt, @joostmeijles, @saltcod, @archanaagivale30, @crutchcorn, @crebelskydico, @Maaz-Ahmed007, @jophy-ye, @remcohaszing, @JoshuaKGoldberg, @creativoma, @GyoHeon, @SukkaW, @MaxLeiter, @neila-a, @stylessh, @Teddir, @ManuLpz4, @Julian-Louis, @syi0808, @mert-duzgun, @amannn, @MonstraG, @hamirmahal, @tariknh, @Kikobeats, @LichuAcu, @Kuboczoch, @himself65, @Sam-Phillemon9493, @Shruthireddy04, @Hemanshu-Upadhyay, @timfuhrmann, @controversial, @pathliving, @mischnic, @mauroaccornero, @NavidNourani, @allanchau, @ekremkenter, @yurivangeffen, @gnoff, @darthmaim, @gdborton, @Willem-Jaap, @KentoMoriwaki, @TrevorSayre, @marlier, @Luluno01, @xixixao, @domin-mnd, @niketchandivade, @N2D4, @kjugi, @luciancah, @mud-ali, @codeSTACKr, @luojiyin1987, @mehmetozguldev, @ronanru, @tknickman, @joelhooks, @khawajaJunaid, @rubyisrust, @abdull-haseeb, @bewinsnw, @housseindjirdeh, @li-jia-nan, @aralroca, @s-ekai, @ah100101, @jantimon, @jordienr, @iscekic, @Strift, @slimbde, @nauvalazhar, @HughHzyb, @guisehn, @wesbos, @OlyaPolya, @paarthmadan, @AhmedBaset, @dineshh-m, @avdeev, @Bhavya031, @MildTomato, @Bjornnyborg, @amikofalvy, @yosefbeder, @kjac, @woutvanderploeg, @Ocheretovich, @ProchaLu, @luismiramirez, @omahs, @theoludwig, @abhi12299, @sommeeeer, @lumirlumir, @royalfig, @iampoul, @molebox, @txxxxc, @zce, @mamuso, @kahlstrm, @vercel-release-bot, @zhawtof, @PapatMayuri, @PlagueFPS, @IDNK2203, @jericopulvera, @liby, @CannonLock, @timfish, @whatisagi, @none23, @haouvw, @Pyr33x, @SouthLink, @frydj, @CrutchTheClutch, @sleevezip, @r34son, @yunsii, @md-rejoyan-islam, @kartheesan05, @nattui, @KonkenBonken, @weicheng95, @brekk, @Francoscopic, @B33fb0n3, @ImDR, @nurullah, @hdodov, @ebCrypto, @soedirgo, @floriangosse, @Tim-Zj, @raeyoung-kim, @erwannbst, @DerTimonius, @hirotomoyamada, @Develliot, @chandanpasunoori, @vicb, @ankur-dwivedi, @kidonng, @baeharam, @AnaTofuZ, @coderfin, @xugetsu, @alessiomaffeis, @kutsan, @jordyfontoura, @sebmarkbage, @tranvanhieu01012002, @jlbovenzo, @Luk-z, @jaredhan418, @bangseongbeom, @penicillin0, @neoFinch, @DeepakBalaraman, @Manoj-M-S, @Unsleeping, @lonr, @Aerilym, @ytori, @acdlite, @actopas, @n-ii-ma, @adcichowski, @mobeigi, @JohnGemstone, 和 @jjm2317 的帮助!