跳到主要內容
回到部落格

2023 年 2 月 23 日,星期四

Next.js 13.2

發布者

Next.js 13.2 包含了 App Router (app) 的重大改進,為穩定性做準備

立即執行以下命令更新

終端機
npm i next@latest react@latest react-dom@latest eslint-config-next@latest

透過新的 Metadata API 內建 SEO 支援

Next.js 從一開始就被設計為啟用搜尋引擎最佳化

提供預先渲染的 HTML 內容不僅有助於改進搜尋引擎的索引,還能提高應用程式的效能。雖然 Next.js 在許多版本中都提供了一個簡單的 API 用於修改應用程式中的 metadata (next/head),但我們希望重新設計和增強您使用 App Router (app) 進行搜尋引擎最佳化的方式。

新的 Metadata API 允許您在任何版面配置或頁面(Server Component)中使用明確的 metadata 設定來定義 metadata(例如 HTML head 元素內的 metalink 標籤)。

app/layout.tsx
import type { Metadata } from 'next';
 
export const metadata: Metadata = {
  title: 'Home',
  description: 'Welcome to Next.js',
};

這個 API 簡單、可組合,並且設計為與串流伺服器渲染相容。例如,您可以在根版面配置中為整個應用程式設定常見的 metadata 屬性,並為應用程式中的其他路由組合和合併 metadata 物件。

這包括對動態 metadata 以及靜態 metadata 的支援

layout.js / page.js
// Static metadata
export const metadata = {
  title: '...',
};
 
// Dynamic metadata
export async function generateMetadata({ params, searchParams }) {
  const product = await getProduct(params.id);
  return { title: product.title };
}

所有 metadata 選項都可用,包括提供自訂 metadata 的能力,並透過 TypeScript 外掛程式 或新增 Metadata 類型來支援 TypeScript。

例如,您可以透過 metadata 定義 Open Graph 圖片

app/layout.tsx
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 目錄。

深入了解 SEO 或查看 Metadata 的 API 參考文件。我們要感謝 next-seo 在社群套件方面的工作以及對初始 API 設計的回饋。

自訂路由處理器

App Router (app) 原始 Beta 版本的遺漏部分之一是 API 路由,它存在於 pages/api 目錄中。我們希望藉此機會創建一個新的、更現代化的 API 路由版本,該版本能深入整合到 app 的新路由系統中。

路由處理器允許您使用 Web RequestResponse API 為給定路由建立自訂請求處理器。

app/example/route.ts
export async function GET(request: Request) {}

路由處理器具有同構 API,可無縫支援 Edge 和 Node.js 執行階段,包括對串流回應的支援。由於路由處理器使用與頁面和版面配置相同的路由區段設定,因此它們支援期待已久的功能,例如通用靜態渲染重新驗證

route.ts 檔案可以匯出由 HTTP 動詞命名的非同步函式:GETHEADOPTIONSPOSTPUTDELETEPATCH。然後可以包裝和抽象這些函式,以為您的自訂路由邏輯建立輔助程式/可重複使用的邏輯。

其他伺服器函式,例如 cookiesheaders,可以在路由處理器內部使用,以及這些抽象概念建立的任何 Web API。這允許在伺服器元件和路由處理器之間共享程式碼。

app/example/route.ts
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 版本中適用於使用 route.ts 特殊檔案的 App Router (app)。它們在 pages 目錄中不可用,因為它們是 API 路由的替代品。

深入了解路由處理器查看 API 參考文件。我們要感謝 SvelteKit 在此提供的先前的技術和啟發

伺服器元件的 MDX

MDX 是 Markdown 的超集,可讓您直接在 Markdown 檔案中編寫 JSX。這是一種在內容中新增動態互動性和嵌入 React 元件的強大方式。

在 13.2 版本中,您現在可以完全將 MDX 與 React 伺服器元件一起使用,這表示更少的用戶端 JavaScript 以實現更快的頁面載入速度,同時保留 React 在範本化動態 UI 方面的強大功能。您可以根據需要將互動性添加到 MDX 內容中。

@next/mdx 外掛程式已更新,支援新的特殊檔案 mdx-components.js|ts,該檔案定義在應用程式的根目錄中以提供自訂元件

your-project/mdx-components.js
// 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 };
}

此外,我們已與社群套件合作,以獲取 MDX 內容 next-mdx-remotecontentlayer,以新增對 React 伺服器元件的支援。

深入了解如何設定具有伺服器元件的 MDX部署我們的範例

Rust MDX 解析器

作為啟用伺服器元件 MDX 的一部分,我們還用 Rust 重寫了 MDX 解析器以提高效能。與之前的基於 JavaScript 的解析器相比,這是一個顯著的改進,後者在處理大量 MDX 檔案時會出現明顯的效能降低。

您可以選擇在 next.config.js 中使用 Rust 解析器。例如,使用 @next/mdx

next.config.js
/** @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。

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    appDir: true,
    typedRoutes: true,
  },
};
 
module.exports = nextConfig;

此功能現已在 Beta 版中提供。目前尚不支援 rewritesredirects

深入了解靜態類型路由.

改良的錯誤覆蓋層

為了幫助提高錯誤的可讀性和可調試性,我們對 Next.js 錯誤覆蓋層進行了一些改進。

在 13.2 版本中,Next.js 和 React 堆疊追蹤現在已分開,從而更容易識別錯誤的來源。此外,錯誤覆蓋層現在顯示 Next.js 的目前版本,幫助您了解您的版本是否為最新版本。

The improved error overlay in 13.2 showing version staleness.
13.2 版本中改良的錯誤覆蓋層顯示版本過時。

我們也改進了 React hydration 錯誤的錯誤輸出,現在更易於閱讀和調試。

Turbopack 改進

Turbopack 在 Next.js 13 中以 Alpha 版發布,是一個增量式捆綁器,旨在加速本地開發以及未來的生產建置。

我們一直專注於在 Turbopack 中支援現有的 Next.js 功能,並在我們朝 Beta 版邁進時提高整體穩定性。自上次發布以來,我們新增了

  • next/dynamic 的支援
  • next.config.js 中支援 rewritesredirectsheaderspageExtensions
  • pages 中支援 404 和錯誤
  • 支援 CSS modules composes: ... from ...
  • 改進了 Fast Refresh 的可靠性和錯誤恢復
  • 改進了 CSS 優先順序處理
  • 改進了編譯時評估

我們還修復了許多錯誤並提高了穩定性,同時透過我們一些最大的內部 Next.js 應用程式和早期的 Vercel 客戶對 Turbopack 進行了內部測試。

使用 Webpack 加載器進行自訂檔案轉換

Turbopack 現在隨附對某些 Webpack 加載器的支援和相容性。這表示您可以使用 Webpack 生態系統中的許多加載器,將不同類型的檔案轉換為 JavaScript。支援 @mdx-js/loader@svgr/webpackbabel-loader 等加載器。深入了解 自訂 Turbopack。

例如,使用 experimental.turbo.loaders 為每個檔案副檔名設定加載器清單

next.config.js
module.exports = {
  experimental: {
    turbo: {
      loaders: {
        '.md': [
          {
            // Option format
            loader: '@mdx-js/loader',
            options: {
              format: 'md',
            },
          },
        ],
        '.svg': ['@svgr/webpack'],
      },
    },
  },
};

查看使用加載器的 Turbopack 範例 以獲得完整的範例。

Webpack 風格的解析別名

Turbopack 現在可以設定為透過別名修改模組解析,類似於 webpack 的 resolve.alias。透過 experimental.turbo.resolveAlias 進行設定

next.config.js
module.exports = {
  experimental: {
    turbo: {
      resolveAlias: {
        underscore: 'lodash',
        mocha: { browser: 'mocha/browser-entry.js' },
      },
    },
  },
};

Next.js 快取

Next.js 13.2 推出了新的 Next.js 快取 (Beta),這是 ISR 的演進,它解鎖了

  • 元件層級的漸進式 ISR
  • 無需網路請求即可更快地刷新
  • 更快地將程式碼變更重新部署到靜態頁面

對於完全靜態的頁面,ISR 的運作方式與今天相同。對於具有更精細資料獲取、混合靜態和動態的頁面,Next.js 快取使用更精細、短暫的快取。

借助 React 伺服器元件和 Next.js App Router (app) 中並置資料獲取的基礎,您現在可以將靜態或動態資料與其消耗元件一起封裝。

app/page.jsx
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 生產環境中相同的快取行為。這提高了任何伺服器元件或資料載入程式碼變更時 Fast Refresh 的速度。

使用 Next.js 快取,您的應用程式控制快取,而不是第三方 API。這與 cache-control 標頭不同,在 cache-control 標頭中,上游控制值的快取時間長度。

具有 Vercel 快取 API 的 Next.js 快取

Vercel 上的 Next.js 為您提供框架定義的基礎架構。您編寫應用程式程式碼,例如使用 fetch 進行元件層級的資料獲取,我們會為您構建全球分散式基礎架構,而無需額外的工作。

新的 Next.js 快取使程式碼變更獨立於資料變更。這可以大幅加速靜態頁面的重新部署,因為這些頁面的產生可以使用現有的快取。

這個新的 Vercel 快取 API 旨在與任何框架協同工作,但與 Next.js 快取具有原生整合。深入了解 ISR 如何演進為 Next.js 快取,以及部署到 Vercel 時 Next.js 快取如何運作。

自行託管時的 Next.js 快取

在自行託管時,使用 LRU 快取,預設為 50 MB。預設情況下,快取中的所有條目都會自動寫入磁碟。如果節點具有相同的快取金鑰,則此檔案系統快取可以在節點之間共享,類似於今天的 ISR 運作方式

對於希望進一步自訂和修改 Next.js 快取核心的開發人員,他們可以修改底層快取金鑰,並更改快取條目的持久化方式和位置,包括完全停用持久化。

其他改進

  • 字型: 繼社群廣泛採用之後,@next/font 現在作為 next/font 內建於 Next.js 中。這表示您不再需要單獨安裝 @next/font深入了解
  • 字型: 根據社群回饋,next/font 的預設 font-display 屬性已從 optional 變更為 font-display: swap
  • 效能: 優化了建置流程以使用更少的記憶體,在我們的測試中節省了約 550MB (PR)。
  • 效能: 避免多次載入專案設定,在我們的測試中,建置速度平均加快約 400 毫秒 (PR)。
  • 效能: 優化了錯誤元件,在不更改樣式的情況下減少了 0.4kb 的 HTML 負載 (PR)。
  • 效能: 將邊緣捆綁包大小減少了約 130KB,幾乎減少了一半的大小,以進一步縮減部署到 Vercel 等邊緣環境時的冷啟動大小 (PR)。
  • 安全性: 新增設定 images.contentDispositionType: "attachment",強制在直接訪問 Image Optimization API 時下載圖片 (PR)。

社群

Next.js 是超過 2,500 位獨立開發者、Google 和 Meta 等產業夥伴,以及我們 Vercel 核心團隊共同努力的成果。Next.js 每週有超過 390 萬次的 npm 下載量和 100,000+ 個 GitHub 星星,是最受歡迎的 Web 建構方式之一。

加入社群,請至 GitHub DiscussionsRedditDiscord

這個版本由以下團隊成員帶來:

以及以下貢獻者:@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。