跳到内容
返回博客

2023年10月26日 星期四

Next.js 14

发布者

正如我们在 Next.js Conf 上宣布的,Next.js 14 是我们最专注的版本,包含:

  • Turbopack:App 和 Pages Router 通过 5,000 项测试
    • 本地服务器启动速度提高 53%
    • 通过快速刷新,代码更新速度提高 94%
  • 服务器操作 (稳定版):渐进式增强的突变
    • 与缓存和重新验证集成
    • 简单的函数调用,或与表单原生配合使用
  • 部分预渲染 (预览版):快速初始静态响应 + 流式动态内容
  • Next.js 学习 (新版):免费课程,教授 App Router、身份验证、数据库等内容。

立即升级或开始使用

终端
npx create-next-app@latest

Next.js 编译器:全面加速

自 Next.js 13 以来,我们一直致力于提高 Pages 和 App Router 中的本地开发性能。

此前,我们重写了 next dev 和 Next.js 的其他部分以支持此项工作。我们后来改变了方法,使其更具增量性。这意味着我们的基于 Rust 的编译器很快将达到稳定状态,因为我们已将重点重新放在首先支持所有 Next.js 功能上。

现在,next dev 的 5,000 项集成测试已通过 Turbopack(我们的底层 Rust 引擎)。这些测试包含了 7 年的错误修复和复现。

vercel.com 这个大型 Next.js 应用程序上进行测试时,我们发现

  • 本地服务器启动速度最高提高 53.3%
  • 通过快速刷新,代码更新速度最高提高 94.7%

此基准测试是大型应用程序(和大型模块图)性能改进的实际结果。目前 next dev 的 90% 测试已通过,因此在使用 next dev --turbo 时,您应该会看到更快速、更可靠的性能。

一旦通过 100% 的测试,我们将在即将发布的小版本中将 Turbopack 转移到稳定版。我们还将继续支持使用 webpack 进行自定义配置和生态系统插件。

您可以在 areweturboyet.com 上关注测试通过的百分比。

表单和突变

Next.js 9 引入了 API 路由——一种快速构建后端端点并与前端代码协同工作的方式。

例如,您可以在 api/ 目录中创建一个新文件

pages/api/submit.ts
import type { NextApiRequest, NextApiResponse } from 'next';
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  const data = req.body;
  const id = await createItem(data);
  res.status(200).json({ id });
}

然后,在客户端,您可以使用 React 和 onSubmit 等事件处理程序向您的 API 路由发送 fetch 请求。

pages/index.tsx
import { FormEvent } from 'react';
 
export default function Page() {
  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
 
    const formData = new FormData(event.currentTarget);
    const response = await fetch('/api/submit', {
      method: 'POST',
      body: formData,
    });
 
    // Handle response if necessary
    const data = await response.json();
    // ...
  }
 
  return (
    <form onSubmit={onSubmit}>
      <input type="text" name="name" />
      <button type="submit">Submit</button>
    </form>
  );
}

现在,通过 Next.js 14,我们希望简化编写数据突变的开发人员体验。此外,我们希望改善用户在网络连接缓慢或从低功耗设备提交表单时的用户体验。

服务器操作 (稳定版)

如果您不需要手动创建 API 路由呢?相反,您可以定义一个在服务器上安全运行的函数,直接从您的 React 组件调用。

App Router 构建在 React canary 频道上,该频道对框架而言是稳定的,可以采用新功能。从 v14 开始,Next.js 已升级到最新的 React canary,其中包含了稳定的服务器操作。

Pages Router 中的上一个示例可以简化为一个文件

app/page.tsx
export default function Page() {
  async function create(formData: FormData) {
    'use server';
    const id = await createItem(formData);
  }
 
  return (
    <form action={create}>
      <input type="text" name="name" />
      <button type="submit">Submit</button>
    </form>
  );
}

对于过去使用过服务器中心框架的开发人员来说,服务器操作应该感觉很熟悉。它基于 Web 基础知识,例如表单和 FormData Web API

虽然通过表单使用服务器操作有助于渐进式增强,但这不是必需的。您也可以将其直接作为函数调用,而无需表单。使用 TypeScript 时,这为您提供了客户端和服务器之间的完整端到端类型安全。

数据修改、页面重新渲染或重定向可以在一次网络往返中完成,确保在客户端显示正确的数据,即使上游提供商速度缓慢。此外,您可以组合和重用不同的操作,包括同一路由中的许多不同操作。

缓存、重新验证、重定向等

服务器操作已深度集成到整个 App Router 模型中。您可以

  • 使用 revalidatePath()revalidateTag() 重新验证缓存数据
  • 通过 redirect() 重定向到不同的路由
  • 通过 cookies() 设置和读取 cookie
  • 使用 useOptimistic() 处理乐观 UI 更新
  • 使用 useFormState() 捕获并显示服务器错误
  • 使用 useFormStatus() 在客户端显示加载状态

了解有关 使用服务器操作的表单和突变服务器组件和服务器操作的安全模型 和最佳实践。

部分预渲染 (预览版)

我们希望分享 Next.js 正在开发的部分预渲染的预览——这是一种针对动态内容的编译器优化,具有快速的初始静态响应。

部分预渲染建立在十年来对服务器端渲染 (SSR)、静态网站生成 (SSG) 和增量静态重新验证 (ISR) 的研究和开发基础之上。

动机

我们已经听取了您的反馈。目前有太多的运行时、配置选项和渲染方法需要考虑。您希望获得静态的速度和可靠性,同时还支持完全动态、个性化的响应。

在全球范围内拥有出色的性能和个性化不应该以复杂性为代价。

我们的挑战是创造更好的开发人员体验,简化现有模型,而无需引入新的 API 供开发人员学习。虽然服务器端内容的部分缓存已经存在,但这些方法仍然需要满足我们所追求的开发人员体验和可组合性目标。

部分预渲染无需学习新的 API。

基于 React Suspense 构建

部分预渲染由您的 Suspense 边界定义。它的工作原理如下。考虑以下电子商务页面

app/page.tsx
export default function Page() {
  return (
    <main>
      <header>
        <h1>My Store</h1>
        <Suspense fallback={<CartSkeleton />}>
          <ShoppingCart />
        </Suspense>
      </header>
      <Banner />
      <Suspense fallback={<ProductListSkeleton />}>
        <Recommendations />
      </Suspense>
      <NewProducts />
    </main>
  );
}

启用部分预渲染后,此页面将根据您的 <Suspense /> 边界生成静态 shell。React Suspense 的 fallback 将被预渲染。

然后,shell 中的 Suspense 回调将替换为动态组件,例如读取 cookie 以确定购物车,或根据用户显示横幅。

当发出请求时,静态 HTML shell 会立即提供

<main>
  <header>
    <h1>My Store</h1>
    <div class="cart-skeleton">
      <!-- Hole -->
    </div>
  </header>
  <div class="banner" />
  <div class="product-list-skeleton">
    <!-- Hole -->
  </div>
  <section class="new-products" />
</main>

由于 <ShoppingCart />cookies 中读取用户会话,因此该组件将作为与静态 shell 相同的 HTTP 请求的一部分进行流式传输。无需额外的网络往返。

app/cart.tsx
import { cookies } from 'next/headers'
 
export default function ShoppingCart() {
  const cookieStore = cookies()
  const session = cookieStore.get('session')
  return ...
}

为了拥有最细粒度的静态 shell,这可能需要添加额外的 Suspense 边界。但是,如果您今天已经在使用 loading.js,这是一个隐式 Suspense 边界,因此无需更改即可生成静态 shell。

即将推出

部分预渲染正在积极开发中。我们将在即将发布的小版本中分享更多更新。

元数据改进

在您的页面内容可以从服务器流式传输之前,需要先将有关视口、配色方案和主题的重要元数据发送到浏览器。

确保这些 meta 标签与初始页面内容一起发送有助于提供流畅的用户体验,防止页面因更改主题颜色或因视口更改而导致布局移动而闪烁。

在 Next.js 14 中,我们解耦了阻塞和非阻塞元数据。只有一小部分元数据选项是阻塞的,我们希望确保非阻塞元数据不会阻止部分预渲染页面提供静态 shell。

以下元数据选项现已弃用,并将在未来的主要版本中从 metadata 中删除

  • viewport:设置视口的初始缩放和其他属性
  • colorScheme:设置视口的支持模式(浅色/深色)
  • themeColor:设置视口周围的浏览器 UI 应渲染的颜色

从 Next.js 14 开始,有新的选项 viewportgenerateViewport 来替换这些选项。所有其他 metadata 选项保持不变。

您可以立即开始采用这些新的 API。现有的 metadata 选项将继续有效。

Next.js 学习课程

今天我们将在 Next.js Learn 上发布一门全新的免费课程。本课程教授

  • Next.js App Router
  • 样式和 Tailwind CSS
  • 优化字体和图像
  • 创建布局和页面
  • 页面间导航
  • 设置您的 Postgres 数据库
  • 使用服务器组件获取数据
  • 静态渲染和动态渲染
  • 流式传输
  • 部分预渲染(可选)
  • 添加搜索和分页
  • 变异数据
  • 错误处理
  • 提高可访问性
  • 添加认证
  • 添加元数据

Next.js Learn 已经向数百万开发人员教授了框架的基础知识,我们迫不及待地想听取您对我们新内容的反馈。前往 nextjs.org/learn 学习这门课程。

其他更改

  • [重大变更] 最低 Node.js 版本现为 18.17
  • [重大变更] 删除了 next-swc 构建的 WASM 目标 (PR)
  • [重大变更] 弃用 @next/font,转而使用 next/font (Codemod)
  • [重大变更] ImageResponse 导入路径从 next/server 更改为 next/og (Codemod)
  • [重大变更] next export 命令已被删除,转而使用 output: 'export' 配置 (文档)
  • [弃用] next/imageonLoadingComplete 已弃用,转而使用 onLoad
  • [弃用] next/imagedomains 已弃用,转而使用 remotePatterns
  • [功能] 可以启用更详细的 fetch 缓存日志记录 (文档)
  • [改进] 基本 create-next-app 应用程序的函数大小减少 80%
  • [改进] 在开发环境中使用 edge 运行时时增强了内存管理

贡献者

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

此版本由以下人员提供

以及以下人员的贡献:@05lazy, @0xadada, @2-NOW, @aarnadlr, @aaronbrown-vercel, @aaronjy, @abayomi185, @abe1272001, @abhiyandhakal, @abstractvector, @acdlite, @adamjmcgrath, @AdamKatzDev, @adamrhunter, @ademilter, @adictonator, @adilansari, @adtc, @afonsojramos, @agadzik, @agrattan0820, @akd-io, @AkifumiSato, @akshaynox, @alainkaiser, @alantoa, @albertothedev, @AldeonMoriak, @aleksa-codes, @alexanderbluhm, @alexkirsz, @alfred-mountfield, @alpha-xek, @andarist, @Andarist, @andrii-bodnar, @andykenward, @angel1254mc, @anonrig, @anthonyshew, @AntoineBourin, @anujssstw, @apeltop, @aralroca, @aretrace, @artdevgame, @artechventure, @arturbien, @Aryan9592, @AviAvinav, @aziyatali, @BaffinLee, @Banbarashik, @bencmbrook, @benjie, @bennettdams, @bertho-zero, @bigyanse, @Bitbbot, @blue-devil1134, @bot08, @bottxiang, @Bowens20832, @bre30kra69cs, @BrennanColberg, @brkalow, @BrodaNoel, @Brooooooklyn, @brunoeduardodev, @brvnonascimento, @carlos-menezes, @cassidoo, @cattmote, @cesarkohl, @chanceaclark, @charkour, @charlesbdudley, @chibicode, @chrisipanaque, @ChristianIvicevic, @chriswdmr, @chunsch, @ciruz, @cjmling, @clive-h-townsend, @colinhacks, @colinking, @coreyleelarson, @Cow258, @cprussin, @craigwheeler, @cramforce, @cravend, @cristobaldominguez95, @ctjlewis, @cvolant, @cxa, @danger-ahead, @daniel-web-developer, @danmindru, @dante-robinson, @darshanjain-entrepreneur, @darshkpatel, @davecarlson, @David0z, @davidnx, @dciug, @delbaoliveira, @denchance, @DerTimonius, @devagrawal09, @DevEsteves, @devjiwonchoi, @devknoll, @DevLab2425, @devvspaces, @didemkkaslan, @dijonmusters, @dirheimerb, @djreillo, @dlehmhus, @doinki, @dpnolte, @Drblessing, @dtinth, @ducanhgh, @DuCanhGH, @ductnn, @duncanogle, @dunklesToast, @DustinsCode, @dvakatsiienko, @dvoytenko, @dylanjha, @ecklf, @EndangeredMassa, @eps1lon, @ericfennis, @escwxyz, @Ethan-Arrowood, @ethanmick, @ethomson, @fantaasm, @feikerwu, @ferdingler, @FernandVEYRIER, @feugy, @fgiuliani, @fomichroman, @Fonger, @ForsakenHarmony, @franktronics, @FSaldanha, @fsansalvadore, @furkanmavili, @g12i, @gabschne, @gaojude, @gdborton, @gergelyke, @gfgabrielfranca, @gidgudgod, @Gladowar, @Gnadhi, @gnoff, @goguda, @greatSumini, @gruz0, @Guilleo03, @gustavostz, @hanneslund, @HarshaVardhanReddyDuvvuru, @haschikeks, @Heidar-An, @heyitsuzair, @hiddenest, @hiro0218, @hotters, @hsrvms, @hu0p, @hughlilly, @HurSungYun, @hustLer2k, @iamarpitpatidar, @ianldgs, @ianmacartney, @iaurg, @ibash, @ibrahemid, @idoob, @iiegor, @ikryvorotenko, @imranbarbhuiya, @ingovals, @inokawa, @insik-han, @isaackatayev, @ishaqibrahimbot, @ismaelrumzan, @itsmingjie, @ivanhofer, @IvanKiral, @jacobsfletch, @jakemstar, @jamespearson, @JanCizmar, @janicklas-ralph, @jankaifer, @JanKaifer, @jantimon, @jaredpalmer, @javivelasco, @jayair, @jaykch, @Jeffrey-Zutt, @jenewland1999, @jeremydouglas, @JesseKoldewijn, @jessewarren-aa, @jimcresswell, @jiwooIncludeJeong, @jocarrd, @joefreeman, @JohnAdib, @JohnAlbin, @JohnDaly, @johnnyomair, @johnta0, @joliss, @jomeswang, @joostdecock, @Josehower, @josephcsoti, @josh, @joshuabaker, @JoshuaKGoldberg, @joshuaslate, @joulev, @jsteele-stripe, @JTaylor0196, @JuanM04, @jueungrace, @juliusmarminge, @Juneezee, @Just-Moh-it, @juzhiyuan, @jyunhanlin, @kaguya3222, @karlhorky, @kevinmitch14, @keyz, @kijikunnn, @kikobeats, @Kikobeats, @kleintorres, @koba04, @koenpunt, @koltong, @konomae, @kosai106, @krmeda, @kvnang, @kwonoj, @ky1ejs, @kylemcd, @labyrinthitis, @lachlanjc, @lacymorrow, @laityned, @Lantianyou, @leerob, @leodr, @leoortizz, @li-jia-nan, @loettz, @lorenzobloedow, @lubakravche, @lucasassisrosa, @lucasconstantino, @lucgagan, @LukeSchlangen, @LuudJanssen, @lycuid, @M3kH, @m7yue, @manovotny, @maranomynet, @marcus-rise, @MarDi66, @MarkAtOmniux, @martin-wahlberg, @masnormen, @matepapp, @matthew-heath, @mattpr, @maxleiter, @MaxLeiter, @maxproske, @meenie, @meesvandongen, @mhmdrioaf, @michaeloliverx, @mike-plummer, @MiLk, @milovangudelj, @Mingyu-Song, @mirismaili, @mkcy3, @mknichel, @mltsy, @mmaaaaz, @mnajdova, @moetazanetan, @mohanraj-r, @molebox, @morganfeeney, @motopods, @mPaella, @mrkldshv, @mrxbox98, @nabsul, @nathanhammond, @nbouvrette, @nekochantaiwan, @nfinished, @Nick-Mazuk, @nickmccurdy, @niedziolkamichal, @niko20, @nikolovlazar, @nivak-monarch, @nk980113, @nnnnoel, @nocell, @notrab, @nroland013, @nuta, @nutlope, @obusk, @okcoker, @oliviertassinari, @omarhoumz, @opnay, @orionmiz, @ossan-engineer, @patrick91, @pauek, @peraltafederico, @Phiction, @pn-code, @pyjun01, @pythagoras-yamamoto, @qrohlf, @raisedadead, @reconbot, @reshmi-sriram, @reyrodrigez, @ricardofiorani, @rightones, @riqwan, @rishabhpoddar, @rjsdnql123, @rodrigofeijao, @runjuu, @Ryan-Dia, @ryo-manba, @s0h311, @sagarpreet-xflowpay, @sairajchouhan, @samdenty, @samsisle, @sanjaiyan-dev, @saseungmin, @SCG82, @schehata, @Schniz, @sepiropht, @serkanbektas, @sferadev, @ShaunFerris, @shivanshubisht, @shozibabbas, @silvioprog, @simonswiss, @simPod, @sivtu, @SleeplessOne1917, @smaeda-ks, @sonam-serchan, @SonMooSans, @soonoo, @sophiebits, @souporserious, @sp00ls, @sqve, @sreetamdas, @stafyniaksacha, @starunaway, @steebchen, @stefanprobst, @steppefox, @steven-tey, @suhaotian, @sukkaw, @SukkaW, @superbahbi, @SuttonJack, @svarunid, @swaminator, @swarnava, @syedtaqi95, @taep96, @taylorbryant, @teobler, @Terro216, @theevilhead, @thepatrick00, @therealrinku, @thomasballinger, @thorwebdev, @tibi1220, @tim-hanssen, @timeyoutakeit, @tka5, @tknickman, @tomryanx, @trigaten, @tristndev, @tunamagur0, @tvthatsme, @tyhopp, @tyler-lutz, @UnknownMonk, @v1k1, @valentincostam, @valentinh, @valentinpolitov, @vamcs, @vasucp1207, @vicsantizo, @vinaykulk621, @vincenthongzy, @visshaljagtap, @vladikoff, @wherehows, @WhoAmIRUS, @WilderDev, @Willem-Jaap, @williamli, @wiredacorn, @wiscaksono, @wojtekolek, @ws-jm, @wxh06, @wyattfry, @wyattjoh, @xiaolou86, @y-tsubuku, @yagogmaisp, @yangshun, @yasath, @Yash-Singh1, @yigithanyucedag, @ykzts, @Yovach, @yutsuten, @yyuemii, @zek, @zekicaneksi, @zignis 和 @zlrlyy