2023 年 10 月 26 日,星期四
Next.js 14
发布者正如我们在 Next.js Conf 上宣布的那样,Next.js 14 是我们最专注的版本,具有:
- Turbopack:5,000 个测试用例通过了 App & Pages Router
- 本地服务器启动速度提升 53%
- 使用 Fast Refresh 代码更新速度提升 94%
- 服务器操作 (稳定版):渐进增强的 mutations
- 与缓存和重新验证集成
- 简单的函数调用,或与表单原生配合使用
- 部分预渲染(预览版):快速初始静态响应 + 流式动态内容
- Next.js 学习 (全新):免费课程,教授 App Router、身份验证、数据库等。
立即升级或开始使用
npx create-next-app@latest
Next.js 编译器:Turbocharged
自 Next.js 13 以来,我们一直致力于提高 Next.js 中 Pages 和 App Router 的本地开发性能。
此前,我们正在重写 next dev
和 Next.js 的其他部分以支持这项工作。 此后,我们改变了方法,使其更具增量性。 这意味着我们基于 Rust 的编译器将很快达到稳定状态,因为我们已将重点重新放在首先支持所有 Next.js 功能上。
现在,使用我们的底层 Rust 引擎 Turbopack,next dev
的 5,000 个集成测试现在均已通过。 这些测试包括 7 年的错误修复和重现。
在 vercel.com
(一个大型 Next.js 应用程序)上进行测试时,我们发现:
- 本地服务器启动速度最多提升 53.3%
- 使用 Fast Refresh 代码更新速度最多提升 94.7%
此基准测试是您在使用大型应用程序(和大型模块图)时应期望的性能改进的实际结果。 随着 next dev
90% 的测试现在通过,当您使用 next dev --turbo
时,您应该会看到更快、更可靠的性能。
一旦我们达到 100% 的测试通过率,我们将在即将发布的小版本中将 Turbopack 升级为稳定版。 我们还将继续支持使用 webpack 进行自定义配置和生态系统插件。
您可以在 areweturboyet.com 上关注测试通过率。
表单和 Mutations
Next.js 9 引入了 API 路由——一种在前端代码旁边快速构建后端端点的方法。
例如,您可以在 api/
目录中创建一个新文件
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
请求。
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,我们希望简化开发人员编写数据 mutations 的体验。 此外,我们希望在用户网络连接缓慢或从低功耗设备提交表单时改善用户体验。
服务器操作(稳定版)
如果您不需要手动创建 API 路由会怎么样? 相反,您可以定义一个在服务器上安全运行的函数,直接从您的 React 组件中调用。
App Router 构建于 React canary
频道之上,该频道对于框架来说是稳定的,可以采用新功能。 从 v14 开始,Next.js 已升级到最新的 React canary
,其中包括稳定的服务器操作。
Pages Router 中之前的示例可以简化为一个文件
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()
在客户端上显示加载状态
详细了解关于使用服务器操作的表单和 Mutations或关于安全模型以及服务器组件和服务器操作的最佳实践。
部分预渲染(预览版)
我们想分享部分预渲染的预览版——一种针对动态内容的编译器优化,具有快速的初始静态响应——我们正在为 Next.js 开发。
部分预渲染建立在对服务器端渲染 (SSR)、静态站点生成 (SSG) 和增量静态重新验证 (ISR) 十年的研究和开发之上。
动机
我们收到了您的反馈。 目前有太多的运行时、配置选项和渲染方法需要考虑。 您希望获得静态的速度和可靠性,同时还支持完全动态的个性化响应。
在全球范围内获得出色的性能和个性化不应以复杂性为代价。
我们的挑战是创建更好的开发人员体验,简化现有模型,而无需引入开发人员需要学习的新 API。 虽然服务器端内容的局部缓存已经存在,但这些方法仍然需要满足我们旨在实现的开发人员体验和可组合性目标。
部分预渲染不需要学习新的 API。
构建于 React Suspense 之上
部分预渲染由您的 Suspense 边界定义。 以下是它的工作原理。 考虑以下电子商务页面
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 fallback 将被替换为动态组件,例如读取 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 请求的一部分流式传输。 无需额外的网络往返。
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
:设置视口周围的 Chrome 应该渲染的颜色
从 Next.js 14 开始,有新的选项 viewport
和 generateViewport
来替换这些选项。 所有其他 metadata
选项保持不变。
您可以立即开始采用这些新的 API。 现有的 metadata
选项将继续有效。
Next.js 学习课程
今天,我们发布了 Next.js 学习上的全新免费课程。 本课程教授:
- Next.js App Router
- 样式和 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/image
的onLoadingComplete
已弃用,转而使用onLoad
- [弃用]
next/image
的domains
已弃用,转而使用remotePatterns
- [功能] 可以启用围绕
fetch
缓存的更详细的日志记录 (文档) - [改进] 基本
create-next-app
应用程序的函数大小缩小 80% - [改进] 在开发中使用
edge
运行时时,增强了内存管理
贡献者
Next.js 是超过 2,900 位个人开发者、行业合作伙伴(如 Google 和 Meta)以及我们在 Vercel 的核心团队共同努力的成果。 加入 GitHub Discussions、Reddit 和 Discord 上的社区。
此版本由以下人员为您带来:
- Next.js 团队:Andrew、Balazs、Jiachi、Jimmy、JJ、Josh、Sebastian、Shu、Steven、Tim、Wyatt 和 Zack。
- Turbopack 团队: Donny、 Justin、 Leah、 Maia、 OJ、 Tobias 和 Will。
- Next.js Learn: Delba、 Steph、 Emil、 Balazs、 Hector 和 Amy。
以及以下贡献者: @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