2023 年 2 月 23 日,星期四
Next.js 13.2
發佈者Next.js 13.2 為 App Router (app
) 帶來了重大改進,為穩定版做好準備。
- 內建 SEO 支援:新的 Metadata API 可設定靜態和動態的
meta
標籤。 - 路由處理器:基於 Web
Request
和Response
建構的客製化請求處理器。 - 伺服器元件的 MDX:在 Markdown 中使用 React 元件(僅限伺服器端)。
- Rust MDX 解析器:使用全新的 Rust 外掛程式,加快 Markdown 解析速度。
- 改進的錯誤覆蓋:將 Next.js 和 React 堆疊追蹤分開,提高可讀性。
- 靜態類型連結(測試版):使用
next/link
和 TypeScript 防止連結失效。 - Turbopack 改進(Alpha 版):與 Webpack 載入器相容,並改進了支援。
- Next.js 快取(測試版):漸進式 ISR 和更快的程式碼變更重新部署。
立即更新:
npm i next@latest react@latest react-dom@latest eslint-config-next@latest
內建 SEO 支援與新的 Metadata API
Next.js 從一開始的設計就著重於搜尋引擎最佳化。
提供預渲染的 HTML 內容不僅有助於提升搜尋引擎的索引,還能改善應用程式的效能。雖然 Next.js 多個版本以來都提供了簡單的 API (next/head
) 來修改應用程式中的詮釋資料,但我們希望重新設計並強化 App Router (app
) 的搜尋引擎最佳化方式。
新的 Metadata API 允許您在任何作為伺服器元件的佈局或頁面中,使用明確的詮釋資料設定來定義詮釋資料(例如 HTML head
元素內的 meta
和 link
標籤)。
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Home',
description: 'Welcome to Next.js',
};
這個 API 簡單、可組合,並且設計與串流伺服器渲染相容。例如,您可以在根佈局中設定整個應用程式的通用詮釋資料屬性,並為應用程式中的其他路由組合和合併詮釋資料物件。
這也包含了對動態詮釋資料以及靜態詮釋資料的支援
// Static metadata
export const metadata = {
title: '...',
};
// Dynamic metadata
export async function generateMetadata({ params, searchParams }) {
const product = await getProduct(params.id);
return { title: product.title };
}
所有詮釋資料選項皆可用,包括提供自訂詮釋資料的功能,並透過TypeScript 外掛程式或新增 Metadata
類型來支援 TypeScript。
例如,您可以透過詮釋資料定義 Open Graph 圖片
export const metadata = {
openGraph: {
title: 'Next.js',
description: 'The React Framework for the Web',
url: 'https://nextjs.dev.org.tw',
siteName: 'Next.js',
images: [
{
url: 'https://nextjs.dev.org.tw/og.png',
width: 800,
height: 600,
},
],
locale: 'en-US',
type: 'website',
},
};
export default function Layout({ children }) {}
Metadata API 在 13.2 版本的 App Router (app
) 中提供,取代了先前的特殊檔案 head.js
。pages
目錄不支援此 API。
深入瞭解 SEO 或檢視Metadata 的 API 參考。我們要感謝next-seo社群套件的開發以及對初始 API 設計的回饋。
自訂路由處理程式
App Router (app
) 最初 Beta 版缺少的部分之一是存在於 pages/api
目錄中的 API 路由。我們希望藉此機會建立一個新的、更現代化的 API 路由版本,並與 app
的新路由系統深度整合。
路由處理器 (Route Handlers) 讓您可以使用 Web Request 和 Response API 為指定的路由建立自訂請求處理器。
export async function GET(request: Request) {}
路由處理器具備同構 API,可無縫支援 Edge 和 Node.js 執行環境,包含串流回應的支援。 由於路由處理器使用與頁面和佈局相同的 路由區段設定,它們支援眾所期待的功能,例如通用 靜態渲染 (Static Rendering) 和 重新驗證 (Revalidation)。
route.ts
檔案可以匯出以 HTTP 動詞命名的非同步函式:GET
、HEAD
、OPTIONS
、POST
、PUT
、DELETE
和 PATCH
。 然後,可以包裝和抽象這些函式,為您的自訂路由邏輯建立輔助程式/可重複使用的邏輯。
其他伺服器函式,例如 cookies
和 headers
,可以在路由處理器內使用,以及這些抽象所基於的任何 Web API。 這允許在伺服器元件和路由處理器之間共享程式碼。
import { cookies } from 'next/headers';
export async function GET(request: Request) {
const cookieStore = cookies();
const token = cookieStore.get('token');
return new Response('Hello, Next.js!', {
status: 200,
headers: { 'Set-Cookie': `token=${token}` },
});
}
在 13.2 版本中,應用程式路由器 (app
) 可以使用 route.ts
特殊檔案來使用路由處理器。 它們在 pages
目錄中不可用,因為它們是 API 路由的替代方案。
深入瞭解路由處理器 或 檢視 API 參考。 我們要感謝 SvelteKit 在這方面的 先前技術和啟發。
伺服器元件的 MDX
MDX 是 markdown 的超集,可讓您直接在 markdown 檔案中編寫 JSX。 它是一種在內容中新增動態互動性和嵌入 React 元件的強大方法。
在 13.2 版本中,您現在可以完全將 MDX 與 React 伺服器元件一起使用,這意味著更少的用戶端 JavaScript,從而加快頁面載入速度,同時保留 React 範本化動態 UI 的強大功能。 您可以根據需要在 MDX 內容中添加互動性。
@next/mdx
外掛程式已更新,支援在應用程式根目錄定義的新特殊檔案 mdx-components.js|ts
,以提供自訂元件。
// This file allows you to provide custom React components
// to be used in MDX files. You can import and use any
// React component you want, including components from
// other libraries.
function H1({ children }) {
// ...
}
function H2({ children }) {
// ...
}
export function useMDXComponents(components) {
return { h1: H1, h2: H2, ...components };
}
此外,我們與社群套件合作,使用 next-mdx-remote
和 contentlayer
來擷取 MDX 內容,並新增對 React 伺服器元件 (Server Components) 的支援。
深入了解如何使用伺服器元件設定 MDX 或 部署我們的範例。
Rust MDX 解析器
作為啟用 MDX 支援伺服器元件的一部分,我們也使用 Rust 重寫了 MDX 解析器以提升效能。相較於先前基於 JavaScript 的解析器,這是一項顯著的改進,先前的解析器在處理大量 MDX 檔案時會出現明顯的效能下降。
您可以在 next.config.js
中選擇使用 Rust 解析器。例如,使用 @next/mdx
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
mdxRs: true,
},
};
const withMDX = require('@next/mdx')();
module.exports = withMDX(nextConfig);
我們要感謝 Titus Wormer,我們贊助他參與這個專案。如果您想在 Next.js 之外使用它,請查看新的套件 mdxjs-rs。
靜態類型連結
Next.js 現在可以在 app
目錄中靜態類型化連結,以防止在使用 next/link
時出現拼寫錯誤和其他錯誤,從而提高頁面間導航時的類型安全性。
import Link from 'next/link'
// ✅
<Link href="/about" />
// ✅
<Link href="/blog/nextjs" />
// ✅
<Link href={`/blog/${slug}`} />
// ❌ TypeScript errors if href is not a valid route
<Link href="/aboot" />
此功能需要使用新的應用程式路由器 (App Router) 以及 TypeScript。
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
typedRoutes: true,
},
};
module.exports = nextConfig;
此功能目前處於 Beta 測試階段。尚不支援 rewrites
和 redirects
。
改進的錯誤覆蓋顯示
為了提高錯誤訊息的可讀性和除錯能力,我們對 Next.js 錯誤覆蓋顯示進行了許多改進。
在 13.2 版本中,Next.js 和 React 的堆疊追蹤現在已分開顯示,更容易識別錯誤的來源。此外,錯誤覆蓋顯示現在會顯示目前的 Next.js 版本,幫助您了解您的版本是否為最新版本。


我們也改進了 React hydration 錯誤的輸出,現在更容易閱讀和除錯。
Turbopack 的改進
在 Next.js 13 中以 alpha 版本發佈的Turbopack,是一個增量式打包器,旨在加快本地開發速度,並在未來加快生產構建速度。
隨著我們邁向 beta 版本,我們一直專注於在 Turbopack 中支援現有的 Next.js 功能並提高整體穩定性。自上次發佈以來,我們新增了
- 支援
next/dynamic
- 支援在
next.config.js
中的rewrites
、redirects
、headers
和pageExtensions
- 支援在
pages
中的 404 和錯誤 - 支援 CSS 模組
composes: ... from ...
- 改進了快速重新整理的可靠性和錯誤恢復
- 改進了 CSS 優先順序的處理
- 改進了編譯時求值
我們還修復了許多錯誤,並在我們一些最大的內部 Next.js 應用程式和早期 Vercel 客戶中使用 Turbopack 進行測試的同時提高了穩定性。
使用 Webpack Loader 進行自訂檔案轉換
Turbopack 現在支援並相容部分 webpack loader。這表示您可以使用 Webpack 生態系統中的許多 loader 將不同類型的檔案轉換為 JavaScript。諸如 @mdx-js/loader
、@svgr/webpack
和 babel-loader
等 loader 都受到支援。深入瞭解如何自訂 Turbopack。
例如,使用 experimental.turbo.loaders
來設定每個檔案副檔名的 loader 列表。
module.exports = {
experimental: {
turbo: {
loaders: {
'.md': [
{
// Option format
loader: '@mdx-js/loader',
options: {
format: 'md',
},
},
],
'.svg': ['@svgr/webpack'],
},
},
},
};
查看使用 loader 的 Turbopack 範例,以獲得完整的範例。
Webpack 風格的解析別名
現在可以設定 Turbopack,透過別名修改模組解析,類似於 webpack 的resolve.alias
。透過 experimental.turbo.resolveAlias
進行設定。
module.exports = {
experimental: {
turbo: {
resolveAlias: {
underscore: 'lodash',
mocha: { browser: 'mocha/browser-entry.js' },
},
},
},
};
Next.js 快取
Next.js 13.2 推出了全新的 Next.js 快取(測試版),這是 ISR 的進化版本,它實現了:
- 元件級別的漸進式 ISR
- 更快的更新,無需網路請求
- 更快速地將程式碼變更重新部署到靜態頁面
對於完全靜態的頁面,ISR 的運作方式與現今相同。對於具有更精細資料提取的頁面(混合靜態和動態),Next.js 快取使用更精細、暫時的快取。
基於 React 伺服器元件和 Next.js App Router (app
) 中的共同定位資料提取,您現在可以將靜態或動態資料與其使用元件封裝在一起。
export default async function Page() {
const [staticData, dynamicData, revalidatedData] = await Promise.all([
// Cached until manually invalidated
fetch(`https://...`),
// Refetched on every request
fetch(`https://...`, { cache: 'no-store' }),
// Cached with a lifetime of 10 seconds
fetch(`https://...`, { next: { revalidate: 10 } }),
]);
return <div>...</div>;
}
在使用 App Router 進行本地開發時,您現在會在 next dev
中看到與 next start
生產環境相同的快取行為。當任何伺服器元件或資料載入程式碼發生變更時,這將提高快速重新整理的速度。
透過 Next.js 快取,您的應用程式可以控制快取,而不是由第三方 API 控制。這與 cache-control
標頭不同,後者由上游控制值快取的時間。
搭配 Vercel 快取 API 的 Next.js 快取
在 Vercel 上的 Next.js 為您提供框架定義的基礎架構。您只需編寫應用程式程式碼,例如使用 fetch
進行元件級別的資料提取,我們就會自動為您建構全球分佈式基礎架構,無需額外的工作。
新的 Next.js 快取讓程式碼的更改與資料的更改分離。這可以大幅加快靜態頁面的重新部署速度,因為這些頁面的生成可以使用現有的快取。
這個新的 Vercel 快取 API 設計用於任何框架,但與 Next.js 快取原生整合。深入瞭解 ISR 如何演變為 Next.js 快取,以及 Next.js 快取部署到 Vercel 時如何運作。
自行託管時的 Next.js 快取
在自行託管時,會使用 LRU 快取,預設為 50 MB。預設情況下,所有快取中的項目都會自動寫入磁碟。如果節點具有相同的快取鍵,則這個檔案系統快取可以在節點之間共享,類似於目前的 ISR 運作方式。
對於希望進一步自訂和修改 Next.js 快取核心的開發人員,他們可以修改底層的快取鍵,並更改快取項目的儲存方式和位置,包括完全停用儲存。
其他改進
- 字體:由於社群採用率驚人,
@next/font
現在已內建於 Next.js 中,成為next/font
。這表示您不再需要另外安裝@next/font
。深入瞭解. - 字體:根據社群的回饋,
next/font
的預設font-display
屬性已從optional
改為font-display: swap
。 - 效能:最佳化建置流程以減少記憶體使用量,在我們的測試中節省了約 550MB 的記憶體 (PR)。
- 效能:避免多次載入專案設定,使建置速度在我們的測試中平均提升約 400 毫秒 (PR)。
- 效能:最佳化錯誤元件,在不改變樣式的情況下減少了 0.4kb 的 HTML 負載量 (PR)。
- 效能:將邊緣套件大小減少了約 130KB,幾乎縮減一半,以進一步降低部署到 Vercel 等邊緣環境時的冷啟動大小 (PR)。
- 安全性:新增了
images.contentDispositionType: "attachment"
設定,以便在直接訪問圖片最佳化 API 時強制下載圖片 (PR)。
社群
Next.js 是超過 2,500 位個別開發者、Google 和 Meta 等產業合作夥伴,以及我們在 Vercel 的核心團隊共同努力的成果。Next.js 每週 npm 下載量超過 390 萬次,GitHub 星標數超過 10 萬,是目前最熱門的網頁建置方式之一。
加入我們的社群,您可以透過 GitHub 討論區、Reddit 以及 Discord 與我們聯繫。
此版本由以下人員貢獻:
- The Next.js team: Balazs, Hannes, Jan, Jiachi, Jimmy, JJ, Josh, Sebastian, Shu, Steven, Tim, Wyatt, and Andrew.
- Turbopack 團隊:Alex、Donny、Justin、Leah、LongYinan、Maia、OJ、Tobias 以及 Will。
以及以下貢獻者的付出:@timneutkens、@loettz、@okcoker、@clive-h-townsend、@shuding、@JanKaifer、@sepiropht、@hanneslund、@huozhi、@aralroca、@balazsorban44、@cristobaldominguez95、@vinaykulk621、@Brooooooklyn、@feedthejim、@samsisle、@MarDi66、@styfle、@therealrinku、@sebmarkbage、@cravend、@hu0p、@kdy1、@ijjk、@juzhiyuan、@IvanKiral、@LukeSchlangen、@wojtekolek、@samdenty、@Josehower、@bennettdams、@SCG82、@mike-plummer、@kwonoj、@David0z、@denchance、@joulev、@wbinnssmith、@alexkirsz、@UnknownMonk、@leerob、@sairajchouhan、@imranbarbhuiya、@jomeswang、@ductnn、@thomasballinger、@chibicode、@jridgewell、@sreetamdas、@Juneezee、@SukkaW、@wyattjoh、@michaeloliverx、@cattmote、@joefreeman、@valentincostam、@qrohlf、@ossan-engineer、@rishabhpoddar、@vasucp1207、@Schniz、@andrii-bodnar、@gergelyke、@abstractvector、@wherehows、@BrodaNoel、@taep96、@abe1272001、@0xadada、@nbouvrette、@teobler、@lubakravche、@molebox 以及 @hiddenest。