Next.js 14 正式發(fā)布,更快、更強(qiáng)、更可靠!
10 月 26 日,Next.js 正式發(fā)布。該版本的主要更新如下:
- Turbopack:App & Pages Router 通過(guò) 5000 個(gè)測(cè)試
- 本地服務(wù)器啟動(dòng)速度提高了 53%
- 通過(guò)快速刷新,代碼更新速度提高 94%
- 服務(wù)端操作(穩(wěn)定):逐步增強(qiáng)的數(shù)據(jù)變更
- 集成了緩存和重新驗(yàn)證
- 簡(jiǎn)單的函數(shù)調(diào)用,或者與表單原生配合工作
- 部分預(yù)渲染(預(yù)覽):快速的初始靜態(tài)響應(yīng) + 流式動(dòng)態(tài)內(nèi)容
- Next.js Learn(全新):教授 App Router、身份驗(yàn)證、數(shù)據(jù)庫(kù)等內(nèi)容的免費(fèi)課程。
可以通過(guò)以下命令來(lái)立即升級(jí)最新版本:
npx create-next-app@latest
Next.js 編譯器
自 Next.js 13 以來(lái),Next 團(tuán)隊(duì)一直致力于提高 Next.js 中 Pages 和 App Router 的本地開發(fā)性能。
之前,Next 團(tuán)隊(duì)通過(guò)重寫 Next.js 的 next dev 和其他部分以實(shí)現(xiàn)這一目標(biāo)。然而,后來(lái)改變了方法,采取了更漸進(jìn)的方式?,F(xiàn)在,重點(diǎn)是首先支持所有 Next.js 的功能,因此基于 Rust 的編譯器很快就會(huì)穩(wěn)定下來(lái)。
Next.js 使用基于 Rust 引擎的 Turbopack,現(xiàn)在已經(jīng)通過(guò)了 5000 個(gè) next dev 的集成測(cè)試。這些測(cè)試涵蓋了過(guò)去 7 年中的錯(cuò)誤修復(fù)和重現(xiàn)。
在大型 Next.js 應(yīng)用 vercel.com 上進(jìn)行測(cè)試時(shí),可以看到:
- 本地服務(wù)器啟動(dòng)速度提高高達(dá) 53.3%
- 通過(guò)快速刷新,代碼更新速度提高高達(dá) 94.7%
該基準(zhǔn)測(cè)試是大型應(yīng)用(和大型模塊圖)性能改進(jìn)的實(shí)際結(jié)果?,F(xiàn)在,next dev 的 90% 測(cè)試已經(jīng)通過(guò),在使用 next dev --turbo 時(shí),應(yīng)該會(huì)看到更快、更可靠的性能表現(xiàn)。
一旦達(dá)到 100% 的測(cè)試通過(guò),將在即將發(fā)布的次要版本中將 Turbopack 移至穩(wěn)定版本。另外,還將繼續(xù)支持使用 webpack 進(jìn)行自定義配置和生態(tài)系統(tǒng)插件。
可以在 areweturboyet.com 上關(guān)注通過(guò)測(cè)試的百分比。
表單和數(shù)據(jù)變更
Next.js 9 引入了 API Routes,這是一種快速構(gòu)建后端端點(diǎn)的方法,可以與前端代碼一起使用。
例如,可以在 api/ 目錄中創(chuàng)建一個(gè)新文件:
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 等事件處理程序來(lái)獲取 API 路由:
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>
);
}
現(xiàn)在,隨著 Next.js 14 的推出,希望簡(jiǎn)化開發(fā)者在編寫數(shù)據(jù)變更時(shí)的體驗(yàn)。此外,還希望在用戶網(wǎng)絡(luò)連接較慢或從低功率設(shè)備提交表單時(shí)改善用戶體驗(yàn)。
服務(wù)端操作(穩(wěn)定)
如果不想手動(dòng)創(chuàng)建 API Route,那么可以定義一個(gè)函數(shù),在服務(wù)端安全地運(yùn)行,并直接從 React 組件中調(diào)用它。
App Router 構(gòu)建在 React canary 通道上,對(duì)于框架 采用新功能來(lái)說(shuō)是穩(wěn)定的。從 v14 開始,Next.js 已升級(jí)到最新的 React canary,其中包括穩(wěn)定的服務(wù)器操作。
App Router 是建立在 React canary 通道上的,這個(gè)通道對(duì)于框架來(lái)采用新功能是穩(wěn)定的。從 v14 開始,Next.js 已經(jīng)升級(jí)到了最新的 React canary 版本,其中包含穩(wěn)定的服務(wù)端操作功能。
前面 Pages Router 的例子可以簡(jiǎn)化為一個(gè)文件:
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>
);
}
服務(wù)端操作對(duì)于之前使用過(guò)服務(wù)端中心框架的開發(fā)者來(lái)說(shuō)應(yīng)該會(huì)很熟悉。它是建立在 Web 基礎(chǔ)知識(shí)(如表單和 FormData Web API)之上的。
通過(guò)表單使用服務(wù)端操作對(duì)于漸進(jìn)增強(qiáng)是有幫助的,但并不是必需的。也可以直接將其作為函數(shù)調(diào)用,而無(wú)需使用表單。在使用 TypeScript 時(shí),這提供了完整的端到端類型安全性,確??蛻舳撕头?wù)端之間的安全性。
數(shù)據(jù)變更、頁(yè)面重新渲染或重定向可以在一次網(wǎng)絡(luò)往返中完成,確保在客戶端上顯示正確的數(shù)據(jù),即使上游提供者的響應(yīng)速度較慢。此外,可以組合和重用不同的操作,包括在同一個(gè)路由中使用多個(gè)不同的操作。
緩存、重新驗(yàn)證、重定向等
服務(wù)端操作深度集成到整個(gè) App Router 模型中。你可以:
- 使用 revalidatePath() 或 revalidateTag() 可以重新驗(yàn)證緩存的數(shù)據(jù)。
- 使用redirect()重定向到不同的路由。
- 使用cookies()設(shè)置和讀取cookie
- 使用 useOptimistic() 處理樂(lè)觀 UI 更新
- 使用 useFormState() 捕獲并顯示來(lái)自服務(wù)端的錯(cuò)誤
- 使用 useFormStatus() 在客戶端顯示加載狀態(tài)
部分預(yù)渲染(預(yù)覽)
Next.js 中正在開發(fā)的部分預(yù)渲染推出了預(yù)覽版,它是一種針對(duì)動(dòng)態(tài)內(nèi)容的編譯器優(yōu)化,可以實(shí)現(xiàn)快速的初始靜態(tài)響應(yīng)。
部分預(yù)渲染建立在對(duì)服務(wù)端渲染(SSR)、靜態(tài)站點(diǎn)生成(SSG)和增量靜態(tài)重新驗(yàn)證(ISR)進(jìn)行了十年的研究和開發(fā)的基礎(chǔ)上。
動(dòng)機(jī)
目前存在過(guò)多的運(yùn)行時(shí)、配置選項(xiàng)和渲染方法需要考慮。希望在享受靜態(tài)網(wǎng)頁(yè)的速度和可靠性的同時(shí),也能支持完全動(dòng)態(tài)、個(gè)性化的響應(yīng)。不過(guò),擁有出色的性能和個(gè)性化體驗(yàn)不應(yīng)以復(fù)雜性為代價(jià)。
面臨的挑戰(zhàn)是創(chuàng)建更好的開發(fā)體驗(yàn),簡(jiǎn)化現(xiàn)有模型,而無(wú)需引入新的需要學(xué)習(xí)的 API。雖然部分緩存服務(wù)端內(nèi)容的方法已經(jīng)存在,但這些方法仍然需要滿足旨在實(shí)現(xiàn)的開發(fā)者體驗(yàn)和可組合性目標(biāo)。
部分預(yù)渲染不需要學(xué)習(xí)新的 API。
建立在 React Suspense 之上
部分預(yù)渲染是由 Suspense 邊界定義的。以下是它的工作原理??紤]以下電子商務(wù)頁(yè)面:
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>
);
}
啟用部分預(yù)渲染后,該頁(yè)面將根據(jù) <Suspense /> 邊界生成靜態(tài)骨架,它包含了頁(yè)面的結(jié)構(gòu)和布局,但不包含動(dòng)態(tài)內(nèi)容。React Suspense 的fallback也會(huì)被預(yù)渲染。
然后,在靜態(tài)骨架中,Suspense 的fallback將被動(dòng)態(tài)組件替換,例如讀取 cookie 來(lái)確定購(gòu)物車內(nèi)容,或者根據(jù)用戶顯示橫幅廣告。
當(dāng)發(fā)出請(qǐng)求時(shí),立即提供靜態(tài) 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 /> 組件需要讀取cookie以查看用戶會(huì)話,因此該組件將作為同一HTTP請(qǐng)求的一部分進(jìn)行流式傳輸,與靜態(tài)骨架一起加載,這樣就不需要額外的網(wǎng)絡(luò)往返。
import { cookies } from 'next/headers'
export default function ShoppingCart() {
const cookieStore = cookies()
const session = cookieStore.get('session')
return ...
}
為了獲得最細(xì)粒度的靜態(tài)骨架,可能需要添加額外的 <Suspense /> 邊界。然而,如果今天已經(jīng)在使用 loading.js,那么這是一個(gè)隱式的 <Suspense /> 邊界,因此不需要更改即可生成靜態(tài)骨架。
即將到來(lái)
部分預(yù)渲染正在積極開發(fā)中,將在即將發(fā)布的次要版本中分享更多更新。
元數(shù)據(jù)改進(jìn)
在頁(yè)面內(nèi)容從服務(wù)端流式傳輸之前,需要先向?yàn)g覽器發(fā)送關(guān)于視口、顏色方案和主題等重要元數(shù)據(jù)。
確保這些meta標(biāo)簽與初始頁(yè)面內(nèi)容一起發(fā)送可以提供流暢的用戶體驗(yàn),防止由于更改主題顏色或視口變化而導(dǎo)致頁(yè)面閃爍或布局偏移。
在 Next.js 14 中,將阻塞和非阻塞的元數(shù)據(jù)解耦。只有一小部分元數(shù)據(jù)選項(xiàng)是阻塞的,希望確保非阻塞的元數(shù)據(jù)不會(huì)阻止部分預(yù)渲染頁(yè)面提供靜態(tài)骨架。
以下元數(shù)據(jù)選項(xiàng)現(xiàn)已棄用,并將在未來(lái)的主要版本中從元數(shù)據(jù)中刪除:
- viewport:設(shè)置視口的初始縮放和其他屬性。
- colorScheme:設(shè)置視口的支持模式(亮/暗)。
- themeColor: 設(shè)置視口周圍的瀏覽器界面應(yīng)該呈現(xiàn)的顏色。
從 Next.js 14 開始,使用新的選項(xiàng) viewport 和 generateViewport 來(lái)替換這些選項(xiàng)。所有其他元數(shù)據(jù)選項(xiàng)保持不變。
Next.js Learn 課程
在 Next.js Learn 上發(fā)布了全新的免費(fèi)課程。本課程教授:
- Next.js App Router
- 樣式和 Tailwind CSS
- 優(yōu)化字體和圖像
- 創(chuàng)建布局和頁(yè)面
- 在頁(yè)面之間導(dǎo)航
- 設(shè)置 Postgres 數(shù)據(jù)庫(kù)
- 使用服務(wù)端組件獲取數(shù)據(jù)
- 靜態(tài)和動(dòng)態(tài)渲染
- 流媒體
- 部分預(yù)渲染(可選)
- 添加搜索和分頁(yè)
- 數(shù)據(jù)變更
- 錯(cuò)誤處理
- 改善無(wú)障礙環(huán)境
- 添加身份驗(yàn)證
- 添加元數(shù)據(jù)
其他更新
- [重大變更] 現(xiàn)在 Node.js 最低版本要求為 18.17。
- [重大變更] 移除了 next-swc 構(gòu)建的 WASM 目標(biāo)。
- [重大變更] 放棄支持 @next/font,轉(zhuǎn)而支持 next/font。
- [重大變更] 將 ImageResponse 導(dǎo)入從 next/server 更改為 next/og。
- [重大變更] next export 命令已棄用,推薦使用 output: 'export'。
- [棄用] next/image 的 onLoadingComplete 已棄用,推薦使用 onLoad。
- [棄用] next/image 的 domains 已棄用,推薦使用 remotePatterns。
- [功能] 可以啟用更詳細(xì)的關(guān)于獲取緩存的日志記錄。
- [改進(jìn)] 基本 create-next-app 應(yīng)用的函數(shù)大小減小了 80%。