跳至内容
返回博客

2023年10月26日,星期四

Next.js 14

发布者

正如我们在Next.js Conf上宣布的那样,Next.js 14 是我们最专注的版本,它包含以下特性:

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

立即升级或使用以下命令开始:

终端
npx create-next-app@latest

Next.js 编译器:涡轮增压

从 Next.js 13 开始,我们一直在努力改进 Next.js 中 Pages 和 App 路由器的本地开发性能。

之前,我们正在重写 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 时,您应该会看到更快速、更可靠的性能。

一旦所有测试都通过,我们将在即将发布的次要版本中将 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 路由器构建在 React 的 canary 频道上,该频道对于框架来说是稳定的,可以采用新功能。从 v14 开始,Next.js 已升级到最新的 React canary,其中包括稳定的服务器操作。

Pages 路由器中的前一个示例可以简化为一个文件

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>
  );
}

对于之前使用过以服务器为中心的框架的任何开发人员来说,服务器操作应该感觉很熟悉。它构建在诸如表单和FormData Web API等 Web 基础知识之上。

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

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

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

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

  • 使用 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 />边界生成一个静态外壳。React Suspense 中的fallback会被预渲染。

然后,外壳中的 Suspense 备用内容将被替换为动态组件,例如读取 cookie 以确定购物车,或根据用户显示横幅。

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

<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读取以查看用户会话,因此该组件作为与静态外壳相同的 HTTP 请求的一部分进行流式传输。无需额外的网络往返。

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

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

即将推出

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

元数据改进

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

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

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

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

  • viewport:设置视口的初始缩放和其他属性
  • colorScheme:设置视口支持的模式(亮/暗)
  • themeColor:设置视口周围的色调应呈现的颜色

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

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

Next.js 学习课程

今天,我们发布了一个全新的免费课程,内容来自Next.js 学习。本课程教授

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

Next.js 学习已经教授了数百万开发者关于框架基础知识,我们迫不及待地想听听您对我们新增内容的反馈。前往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 是超过 2900 位独立开发者、Google 和 Meta 等行业合作伙伴以及我们在 Vercel 的核心团队共同努力的结果。加入社区,参与 GitHub 讨论RedditDiscord

此版本由以下人员贡献

感谢以下贡献者:@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、@moetazaneta、@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