Back返回博客

Next.js 14.1 版本发布

Next.js 14.1 版本包含了对自托管、错误提示、并行与拦截路由、Turbopack 等方面的改进。

Next.js 14.1 版本包含以下开发者体验改进:

立即升级或通过以下命令创建新项目:

终端
npx create-next-app@latest

自托管功能增强

我们听取了您关于如何通过 Node.js 服务器、Docker 容器或静态导出方式自托管 Next.js 的反馈,现已全面更新相关文档:

在 Next.js 14.1 中,我们还稳定了针对增量静态生成(ISR)的自定义缓存处理器,以及为应用路由提供更细粒度的数据缓存:

next.config.js
module.exports = {
  cacheHandler: require.resolve('./cache-handler.js'),
  cacheMaxMemorySize: 0, // 禁用默认内存缓存
};

在使用 Kubernetes 等容器编排平台时,此配置尤为重要——因为每个 pod 都会持有缓存副本。自定义缓存处理器能确保所有托管 Next.js 应用的 pod 保持缓存一致性。

例如,您可以将缓存值存储在任何地方,如 Redis 或 Memcached。特别感谢 @neshca 提供的 Redis 缓存处理器适配器 及示例代码。

Turbopack 改进

我们持续优化 Next.js 本地开发的可靠性与性能:

  • 可靠性:Turbopack 已通过完整的 Next.js 开发测试套件,并在 Vercel 内部应用中实战检验
  • 性能:提升 Turbopack 初始编译时间和快速刷新(Fast Refresh)速度
  • 内存占用:优化 Turbopack 内存使用效率

我们计划在后续版本中稳定 next dev --turbo 功能,目前仍为可选特性。

可靠性

使用 Turbopack 的 Next.js 现已通过 5,600 项开发测试(94%),较上次更新新增 600 项。您可以通过 areweturboyet.com 追踪进展。

我们已在 Vercel 所有 Next.js 应用(包括 vercel.comv0.dev)中全面启用 next dev --turbo。开发这些应用的工程师们每天都在使用 Turbopack。

针对超大型 Next.js 应用,我们发现并修复了若干 Turbopack 相关问题,并将这些修复案例新增至 Next.js 的测试套件中。

性能

在大型应用 vercel.com 中,我们观察到:

  • 本地服务启动速度 最高提升 76.7%
  • 代码更新时的快速刷新速度 最高提升 96.3%
  • 无缓存时的初始路由编译速度 最高提升 45.8%(Turbopack 暂未实现磁盘缓存)

v0.dev 中,我们优化了 Turbopack 发现和打包 React 客户端组件的方式,使得初始编译时间 最高减少 61.5%,该优化在 vercel.com 中也得到验证。

未来改进

当前 Turbopack 采用内存缓存机制来加速快速刷新时的增量编译。

但重启开发服务器时缓存不会保留。下一步性能优化的重点是实现 磁盘缓存,使得开发服务器重启后仍能保留缓存。

开发者体验优化

错误提示与快速刷新改进

我们深知清晰的错误提示对本地开发体验至关重要。本次更新优化了 next dev 运行时的堆栈追踪与错误提示:

  • 原先显示为 webpack-internal 的打包器错误,现在能正确显示错误源码及对应文件
  • 修复了客户端组件报错后,即使代码修正仍需要强制刷新才能清除错误界面的问题。例如从客户端组件导出 metadata 的场景

改进前错误提示示例:

Next.js 14 中 fetch 调用报错的旧版提示

Next.js 14.1 已优化为:

渲染过程中 fetch 报错现在会显示错误源码及对应文件

window.history.pushStatewindow.history.replaceState

应用路由现在支持使用原生 pushStatereplaceState 方法来更新浏览器历史记录栈而无需刷新页面。

这些调用会与 Next.js 应用路由集成,保持与 usePathnameuseSearchParams 的同步。

此特性特别适用于需要即时更新 URL 的场景,例如保存筛选条件、排序规则等需要持久化的状态。

'use client';
 
import { useSearchParams } from 'next/navigation';
 
export default function SortProducts() {
  const searchParams = useSearchParams();
 
  function updateSorting(sortOrder: string) {
    const params = new URLSearchParams(searchParams.toString());
    params.set('sort', sortOrder);
    window.history.pushState(null, '', `?${params.toString()}`);
  }
 
  return (
    <>
      <button onClick={() => updateSorting('asc')}>升序排序</button>
      <button onClick={() => updateSorting('desc')}>降序排序</button>
    </>
  );
}

详细了解如何结合使用 原生 History API 与 Next.js。

数据缓存日志

为了提升 Next.js 应用在 next dev 运行时的缓存数据可观测性,我们对 logging 配置选项 进行了多项改进。

现在可以显示缓存是 HIT(命中)还是 SKIP(跳过),以及请求的完整 URL:

终端
GET / 200 in 48ms
 Compiled /fetch-cache in 117ms
 GET /fetch-cache 200 in 165ms
 GET https://api.vercel.app/products/1 200 in 14ms (cache: HIT)
 Compiled /fetch-no-store in 150ms
 GET /fetch-no-store 200 in 548ms
 GET https://api.vercel.app/products/1 200 in 345ms (cache: SKIP)
  Cache missed reason: (cache: no-store)

可通过 next.config.js 启用此功能:

next.config.js
module.exports = {
  logging: {
    fetches: {
      fullUrl: true,
    },
  },
};

next/image<picture> 和艺术指导的支持

Next.js 的 Image 组件现在通过 getImageProps()(稳定版)支持更多高级用例,无需直接使用 <Image>。包括:

import { getImageProps } from 'next/image';
 
export default function Page() {
  const common = { alt: 'Hero', width: 800, height: 400 };
  const {
    props: { srcSet: dark },
  } = getImageProps({ ...common, src: '/dark.png' });
  const {
    props: { srcSet: light, ...rest },
  } = getImageProps({ ...common, src: '/light.png' });
 
  return (
    <picture>
      <source media="(prefers-color-scheme: dark)" srcSet={dark} />
      <source media="(prefers-color-scheme: light)" srcSet={light} />
      <img {...rest} />
    </picture>
  );
}

了解更多关于 getImageProps() 的信息。

并行路由与拦截路由

在 Next.js 14.1 中,我们对并行路由与拦截路由进行了 20 项改进

过去两个版本中,我们专注于提升 Next.js 的性能和可靠性。现在,根据您的反馈,我们对 并行路由拦截路由 进行了多项改进,特别是新增了对全匹配路由和服务器操作的支持。

  • 并行路由 允许您在同一布局中同时或有条件地渲染一个或多个页面。对于应用中的高度动态部分(如社交网站的仪表板和动态流),并行路由可用于实现复杂的路由模式。
  • 拦截路由 允许您在当前布局中加载应用中其他部分的路由。例如,点击动态流中的照片时,可以在模态框中显示照片,覆盖在动态流上方。此时,Next.js 会拦截 /photo/123 路由,隐藏 URL 并将其覆盖在 /feed 上。

了解更多关于 并行路由拦截路由 的信息,或 查看示例

其他改进

14.0 版本以来,我们修复了社区中许多高票反馈的 bug。

我们还发布了视频 解释缓存机制App Router 常见错误,您可能会觉得有帮助。

  • [文档] 新增 重定向 文档
  • [文档] 新增 测试 文档
  • [文档] 新增 生产环境检查清单 文档
  • [功能]next/third-parties 中新增 <GoogleAnalytics /> 组件 (文档)
  • [改进] create-next-app 现在体积更小,安装更快 (PR)
  • [改进] 嵌套路由抛出错误时仍可被 global-error 捕获 (PR)
  • [改进] redirect 现在在服务器操作中会尊重 basePath (PR)
  • [改进] 修复 next/scriptbeforeInteractive 在 App Router 中的使用 (PR)
  • [改进] 自动转译 @aws-sdklodash 以加快路由启动 (PR)
  • [改进] 修复 next devnext/font 导致的未样式内容闪烁问题 (PR)
  • [改进]notFound 错误传播到段错误边界之外 (PR)
  • [改进] 修复 Pages Router i18n 在本地化域名下提供公共文件的问题 (PR)
  • [改进] 当传入无效的 revalidate 值时抛出错误 (PR)
  • [改进] 修复 Windows 构建在 Linux 机器上的路径问题 (PR)
  • [改进] 修复多区域应用使用 basePath 时的快速刷新/HMR 问题 (PR)
  • [改进] 改进终止信号时的优雅关闭 (PR)
  • [改进] 修复从不同路由拦截时的模态路由冲突 (PR)
  • [改进] 修复使用 basePath 配置时的拦截路由问题 (PR)
  • [改进] 当并行插槽缺失导致 404 时显示警告 (PR)
  • [改进] 改进拦截路由与全匹配路由的配合 (PR)
  • [改进] 改进拦截路由与 revalidatePath 的配合 (PR)
  • [改进] 修复并行路由中 @children 插槽的使用 (PR)
  • [改进] 修复并行路由中使用参数时的 TypeError (PR)
  • [改进] 修复默认并行路由的全匹配路由规范化 (PR)
  • [改进] 修复 next build 摘要中并行路由的显示 (PR)
  • [改进] 修复拦截路由使用时的路由参数问题 (PR)
  • [改进] 改进深度嵌套的并行/拦截路由 (PR)
  • [改进] 修复拦截路由与路由组配对时的 404 问题 (PR)
  • [改进] 修复并行路由与服务器操作/路由缓存重新验证的配合 (PR)
  • [改进] 修复拦截路由与 rewrites 的配合 (PR)
  • [改进] 服务器操作现在可在第三方库中使用 (PR)
  • [改进] Next.js 现在可在 ESM 包中使用 (PR)
  • [改进] 针对 Material UI 等库的 Barrel 文件优化 (PR)
  • [改进] 现在会在错误使用 useSearchParams 而没有 Suspense 时使构建失败 (PR)

贡献者

Next.js 是 3,000 多名独立开发者、Google 和 Meta 等行业合作伙伴以及 Vercel 核心团队共同努力的成果。加入 GitHub DiscussionsRedditDiscord 上的社区。

本版本由以下人员共同打造:

以及以下贡献者:@OlehDutchenko, @eps1lon, @ebidel, @janicklas-ralph, @JohnPhamous, @chentsulin, @akawalsky, @BlankParticle, @dvoytenko, @smaeda-ks, @kenji-webdev, @rv-david, @icyJoseph, @dijonmusters, @A7med3bdulBaset, @jenewland1999, @mknichel, @kdy1, @housseindjirdeh, @max-programming, @redbmk, @SSakibHossain10, @jamesmillerburgess, @minaelee, @officialrajdeepsingh, @LorisSigrist, @yesl-kim, @StevenKamwaza, @manovotny, @mcexit, @remcohaszing, @ryo-manba, @TranquilMarmot, @vinaykulk621, @haritssr, @divquan, @IgorVaryvoda, @LukeSchlangen, @RiskyMH, @ash2048, @ManuWeb3, @msgadi, @dhayab, @ShahriarKh, @jvandenaardweg, @DestroyerXyz, @SwitchBladeAK, @ianmacartney, @justinh00k, @tiborsaas, @ArianHamdi, @li-jia-nan, @aramikuto, @jquinc30, @samcx, @Haosik, @AkifumiSato, @arnabsen, @nfroidure, @clbn, @siddtheone, @zbauman3, @anthonyshew, @alexfradiani, @CalebBarnes, @adk96r, @pacexy, @hichemfantar, @michaldudak, @redonkulus, @k-taro56, @mhughdo, @tknickman, @shumakmanohar, @vordgi, @hamirmahal, @gaspar09, @JCharante, @sjoerdvanBommel, @mass2527, @N-Ziermann, @tordans, @davidthorand, @rmathew8-gh, @chriskrogh, @shogunsea, @auipga, @SukkaW, @agustints, @OXXD, @clarencepenz, @better-salmon, @808vita, @coltonehrman, @tksst, @hugo-syn, @JakobJingleheimer, @Willem-Jaap, @brandonnorsworthy, @jaehunn, @jridgewell, @gtjamesa, @mugi-uno, @kentobento, @vivianyentran, @empflow, @samennis1, @mkcy3, @suhaotian, @imevanc, @d3lm, @amannn, @hallatore, @Dylan700, @mpsq, @mdio, @christianvuerings, @karlhorky, @simonhaenisch, @olci34, @zce, @LavaToaster, @rishabhpoddar, @jirihofman, @codercor, @devjiwonchoi, @JackieLi565, @thoushif, @pkellner, @jpfifer, @quisido, @tomfa, @raphaelbadia, @j9141997, @hongaar, @MadCcc, @luismulinari, @dumb-programmer, @nonoakij, @franky47, @robbertstevens, @bryndyment, @marcosmartini, @functino, @Anisi, @AdonisAgelis, @seangray-dev, @prkagrawal, @heloineto, @kn327, @ihommani, @MrNiceRicee, @falsepopsky, @thomasballinger, @tmilewski, @Vadman97, @dnhn, @RodrigoTomeES, @sadikkuzu, @gffuma, @Schniz, @joulev, @Athrun-Judah, @rasvanjaya21, @rashidul0405, @nguyenbry, @Mwimwii, @molebox, @mrr11k, @philwolstenholme, @IgorKowalczyk, @Zoe-Bot, @HanCiHu, @JackHowa, @goncy, @hirotomoyamada, @pveyes, @yeskunall, @ChendayUP, @hmaesta, @ajz003, @its-kunal, @joelhooks, @blurrah, @tariknh, @Vinlock, @Nayeem-XTREME, @aziyatali, @aspehler, 和 @moka-ayumu。