Back返回部落格

Next.js 13

Next.js 13 引入了應用程式目錄中的版面配置 (Layouts)、React 伺服器元件 (Server Components) 和串流 (Streaming) 功能, 同時包含 Turbopack、改進的圖片元件以及全新的字型元件。

如同我們在 Next.js Conf 所宣布的,Next.js 13(穩定版)為動態功能奠定了無限可能的基礎:

Next.js 13 和 pages 目錄已穩定並可投入生產環境。立即執行以下指令更新:

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

新版 app 目錄 (Beta)

今天,我們透過引入 app 目錄來改進 Next.js 的路由和版面配置體驗,並與 React 的未來發展方向保持一致。這是先前發布的 Layouts RFC 的後續行動,該 RFC 曾徵求社群意見。

app 目錄目前處於 beta 階段,我們還不建議在生產環境中使用。您可以在 Next.js 13 中使用穩定的 pages 目錄功能,如改進的 next/imagenext/link 元件,並按自己的步調嘗試 app 目錄。pages 目錄在可預見的未來將持續獲得支援。

app 目錄包含以下功能:

您可以從現有的 pages/ 目錄逐步採用 app 目錄。

您可以從現有的 pages/ 目錄逐步採用 app 目錄。

版面配置 (Layouts)

app/ 目錄讓您能輕鬆佈局複雜的介面,這些介面能在導航間保持狀態、避免昂貴的重新渲染,並實現進階路由模式。此外,您可以嵌套版面配置,並將應用程式碼(如元件、測試和樣式)與路由放在一起。

您可以在 app/ 目錄中將應用程式碼(如元件、測試和樣式)與路由放在一起。

您可以在 app/ 目錄中將應用程式碼(如元件、測試和樣式)與路由放在一起。

app/ 中建立路由只需要一個檔案 page.js

app/page.js
// 此檔案對應到首頁路由 (/)
export default function Page() {
  return <h1>Hello, Next.js!</h1>;
}

然後您可以透過檔案系統定義版面配置。版面配置在多個頁面間共享 UI。在導航時,版面配置會保持狀態、維持互動性且不會重新渲染。

app/blog/layout.js
export default function BlogLayout({ children }) {
  return <section>{children}</section>;
}

了解更多關於版面配置和頁面的資訊部署範例試用

伺服器元件 (Server Components)

app/ 目錄引入了對 React 新的 伺服器元件 (Server Components) 架構的支援。伺服器元件和 客戶端元件 (Client Components) 分別利用伺服器和客戶端的優勢,讓您能用單一的程式設計模型構建快速、高度互動的應用程式,同時提供出色的開發體驗。

透過伺服器元件,我們奠定了構建複雜介面的基礎,同時減少傳送到客戶端的 JavaScript 數量,實現更快的初始頁面載入。

當路由載入時,Next.js 和 React 的運行時會被載入,其大小是可快取且可預測的。這個運行時不會隨著應用程式的增長而變大。此外,運行時是非同步載入的,讓伺服器的 HTML 能在客戶端逐步增強。

了解更多關於伺服器元件的資訊部署範例試用

串流 (Streaming)

app/ 目錄引入了逐步渲染和增量串流渲染 UI 單元到客戶端的能力。

透過伺服器元件和 Next.js 中的 嵌套版面配置,您能立即渲染不需要特定資料的頁面部分,並為正在獲取資料的頁面部分顯示 載入狀態。透過這種方式,使用者無需等待整個頁面載完就能開始與之互動。

您可以將應用程式碼(如元件、測試和樣式)與路由放在一起。

您可以將應用程式碼(如元件、測試和樣式)與路由放在一起。

當部署到 Vercel 時,使用 app/ 目錄的 Next.js 13 應用程式預設會在 Node.js 和 Edge 運行時中串流響應,以提高效能。

了解更多關於串流的資訊部署範例試用

資料獲取 (Data Fetching)

React 最近的 支援 Promise 的 RFC 引入了一種強大的新方式來獲取資料並在元件內處理 Promise:

app/page.js
async function getData() {
  const res = await fetch('https://api.example.com/...');
  // 返回值不會被序列化
  // 您可以返回 Date、Map、Set 等
  return res.json();
}
 
// 這是一個非同步伺服器元件
export default async function Page() {
  const data = await getData();
 
  return <main>{/* ... */}</main>;
}

原生的 fetch Web API 也在 React 和 Next.js 中得到了擴展。它會 自動去重複的 fetch 請求,並提供一種靈活的方式在元件級別獲取、快取和重新驗證資料。這意味著靜態網站生成 (SSG)、伺服器端渲染 (SSR) 和增量靜態再生 (ISR) 的所有好處現在都可以透過一個 API 獲得:

// 此請求應快取直到手動失效。
// 類似於 `getStaticProps`。
// `force-cache` 是預設值,可以省略。
fetch(URL, { cache: 'force-cache' });
 
// 此請求應在每次請求時重新獲取。
// 類似於 `getServerSideProps`。
fetch(URL, { cache: 'no-store' });
 
// 此請求應快取且有效期為 10 秒。
// 類似於 `getStaticProps` 的 `revalidate` 選項。
fetch(URL, { next: { revalidate: 10 } });

app 目錄中,您可以在 版面配置、頁面 和元件內獲取資料,包括支援從伺服器 串流響應

我們正在實現符合人體工學的方式來處理載入和錯誤狀態,並在 UI 渲染時串流顯示。在未來的版本中,我們還將改進和簡化資料變更。

透過 app/ 目錄,您可以使用新的特殊檔案 loading.js 自動建立帶有 Suspense 邊界的即時載入 UI。

透過 app/ 目錄,您可以使用新的特殊檔案 loading.js 自動建立帶有 Suspense 邊界的即時載入 UI。

我們很高興能與開源社群、套件維護者和貢獻於 React 生態系統的其他公司合作,共同為 React 和 Next.js 的新時代構建功能。將資料獲取與元件放在一起並減少傳送到客戶端的 JavaScript 數量是社群反饋的兩個重要方面,我們很高興能在 app/ 目錄中包含這些功能。

了解更多關於資料獲取的資訊部署範例試用

介紹 Turbopack (Alpha)

Next.js 13 包含 Turbopack,這是基於 Rust 的新一代 Webpack 替代方案。

Webpack 已被下載超過 30 億次。雖然它是構建網路的重要部分,但我們已經達到了基於 JavaScript 的工具在效能上的極限。

在 Next.js 12 中,我們開始轉向原生 Rust 驅動的工具。我們首先從 Babel 遷移,這使得轉譯速度提高了 17 倍。然後,我們替換了 Terser,這使得縮小速度提高了 6 倍。現在是時候全面轉向原生的打包工具了。

在 Next.js 13 中使用 Turbopack alpha 版可以實現:

  • 更新速度比 Webpack 快 700 倍
  • 更新速度比 Vite 快 10 倍
  • 冷啟動速度比 Webpack 快 4 倍

Turbopack 是我們基於 Rust 的 Webpack 繼任者,對於大型應用程式的 HMR 速度快了 700 倍。

Turbopack 是我們基於 Rust 的 Webpack 繼任者,對於大型應用程式的 HMR 速度快了 700 倍。

Turbopack 在開發環境中只打包所需的最少資源,因此啟動時間極快。在一個有 3,000 個模組的應用程式上,Turbopack 只需 1.8 秒啟動,Vite 需要 11.4 秒,而 Webpack 需要 16.5 秒。

Turbopack 開箱即用支援伺服器元件、TypeScript、JSX、CSS 等。在 alpha 階段,許多功能 尚未支援。我們很樂意聽取您使用 Turbopack 加速本地迭代的反饋。

注意: Next.js 中的 Turbopack 目前僅支援 next dev。查看 支援的功能。我們也正在努力透過 Turbopack 增加對 next build 的支援。

立即在 Next.js 13 中試用 Turbopack alpha 版,使用 next dev --turbo

next/image

Next.js 13 引入了一個強大的新圖片元件,讓您能輕鬆顯示圖片而不會造成版面位移,並按需優化檔案以提高效能。

在 Next.js 社群調查中,70% 的受訪者表示他們在生產環境中使用 Next.js 圖片元件,並因此看到了核心網頁指標的改善。在 Next.js 13 中,我們進一步改進了 next/image

新的圖片元件:

  • 傳送更少的客戶端 JavaScript
  • 更易於樣式化和配置
  • 預設需要 alt 標籤以提高可訪問性
  • 與網路平台保持一致
  • 更快速,因為原生延遲載入不需要水合作用
app/page.js
import Image from 'next/image';
import avatar from './lee.png';
 
export default function Home() {
  // 現在 "alt" 是必需的,以提高可訪問性
  // 可選:圖片檔案可以放在 app/ 目錄中
  return <Image alt="leeerob" src={avatar} placeholder="blur" />;
}

了解更多關於圖片元件的資訊部署範例試用

升級 next/image 至 Next.js 13

舊的圖片元件已更名為 next/legacy/image。我們提供了一個 codemod,可以自動將您現有的 next/image 使用更新為 next/legacy/image。例如,從根目錄執行以下指令會在您的 ./pages 目錄上運行 codemod:

終端機
npx @next/codemod next-image-to-legacy-image ./pages

了解更多關於 codemod 的資訊

@next/font

Next.js 13 引入了一個全新的字型系統,具有以下特點:

  • 自動優化您的字型,包括自訂字型
  • 移除外部網路請求以提高隱私和效能
  • 內建自動自托管任何字型檔案
  • 使用 CSS size-adjust 屬性自動實現零版面位移

這個新的字型系統讓您能方便地使用所有 Google 字型,同時兼顧效能和隱私。CSS 和字型檔案會在構建時下載,並與其他靜態資源一起自托管。瀏覽器不會向 Google 發送任何請求。

app/layout.js / pages/_app.js
import { Inter } from '@next/font/google';
 
const inter = Inter();
 
<html className={inter.className}></html>;

也支援自訂字型,包括自動自托管、快取和預載字型檔案。

app/layout.js / pages/_app.js
import localFont from '@next/font/local';
 
const myFont = localFont({ src: './my-font.woff2' });
 
<html className={myFont.className}></html>;

您可以自訂字型載入體驗的每個部分,同時確保出色的效能和零版面位移,包括 font-display、預載、後備方案等。

了解更多關於新字型元件的資訊部署範例試用

next/link 不再需要手動添加 <a> 作為子元素。

這在 12.2 版 中作為實驗性選項加入,現在已成為預設行為。在 Next.js 13 中,<Link> 總是渲染一個 <a>,並允許您將屬性傳遞給底層標籤。例如:

import Link from 'next/link'
 
// Next.js 12:必須嵌套 `<a>`,否則會被排除
<Link href="/about">
  <a>About</a>
</Link>
 
// Next.js 13:`<Link>` 總是渲染 `<a>`
<Link href="/about">
  About
</Link>

了解更多關於改進的 Link 元件的資訊部署範例試用

要將您的連結升級至 Next.js 13,我們提供了一個程式碼轉換工具 (codemod),可自動更新您的程式碼庫。例如,以下命令會在專案根目錄執行時,針對 ./pages 目錄進行轉換:

Terminal
npx @next/codemod new-link ./pages

深入了解程式碼轉換工具 或查看相關文件。

OG 圖片生成

社交卡片 (social cards),又稱為開放圖譜圖片 (open graph images),能大幅提升內容點擊率,部分實驗顯示轉換率可提高達 40%。

靜態社交卡片不僅耗時、容易出錯,且難以維護。因此,社交卡片經常被忽略甚至直接跳過。直到今日,需要即時個人化與計算的動態社交卡片仍舊難以實現且成本高昂。

我們開發了全新的 @vercel/og 函式庫,可與 Next.js 無縫整合以生成動態社交卡片。

pages/api/og.jsx
import { ImageResponse } from '@vercel/og';
 
export const config = {
  runtime: 'experimental-edge',
};
 
export default function () {
  return new ImageResponse(
    (
      <div
        style={{
          display: 'flex',
          fontSize: 128,
          background: 'white',
          width: '100%',
          height: '100%',
        }}
      >
        Hello, World!
      </div>
    ),
  );
}

此方法採用 Vercel Edge Functions、WebAssembly 及全新的核心函式庫,將 HTML 和 CSS 轉換為圖片,並利用 React 元件抽象化,速度比現有解決方案快 5 倍

深入了解 OG 圖片生成部署範例親自體驗

中介層 (Middleware) API 更新

在 Next.js 12 中,我們引入了中介層 (Middleware),讓 Next.js 路由器的使用更加靈活。根據開發者的回饋,我們新增了一些功能來改善開發體驗並增加強大的新功能。

現在您可以更輕鬆地在請求中設定標頭:

middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
 
export function middleware(request: NextRequest) {
  // 複製請求標頭並設定新標頭 `x-version`
  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-version', '13');
 
  // 您也可以在 NextResponse.rewrite 中設定請求標頭
  const response = NextResponse.next({
    request: {
      // 新請求標頭
      headers: requestHeaders,
    },
  });
 
  // 設定新的回應標頭 `x-version`
  response.headers.set('x-version', '13');
  return response;
}

現在您也可以直接從中介層提供回應,而無需使用 rewriteredirect

middleware.ts
import { NextRequest, NextResponse } from 'next/server';
import { isAuthenticated } from '@lib/auth';
 
// 將中介層限制在 `/api/` 開頭的路徑
export const config = {
  matcher: '/api/:function*',
};
 
export function middleware(request: NextRequest) {
  // 呼叫驗證函式檢查請求
  if (!isAuthenticated(request)) {
    // 回傳 JSON 格式的錯誤訊息
    return NextResponse.json(
      {
        success: false,
        message: '驗證失敗',
      },
      {
        status: 401,
      },
    );
  }
}

目前從中介層發送回應需要在 next.config.js 中設定 experimental.allowMiddlewareResponseBody 選項。

重大變更

  • React 最低版本從 17.0.2 提升至 18.2.0。
  • Node.js 最低版本從 12.22.0 提升至 14.6.0,因為 12.x 已結束支援 (PR)。
  • swcMinify 設定屬性從 false 改為 true。詳見 Next.js 編譯器
  • next/image 導入名稱改為 next/legacy/image,而 next/future/image 則改為 next/image提供程式碼轉換工具 可安全且自動地重新命名導入。
  • next/link 的子元素不再允許使用 <a>。若要使用舊版行為,請添加 legacyBehavior 屬性,或移除 <a> 以升級。提供程式碼轉換工具 可自動升級您的程式碼。
  • User-Agent 為爬蟲時,路由將不再預先獲取 (prefetch)。
  • 已移除 next.config.js 中棄用的 target 選項。
  • 支援的瀏覽器變更為放棄 Internet Explorer 並以現代瀏覽器為目標。您仍可使用 Browserslist 調整目標瀏覽器。
    • Chrome 64+
    • Edge 79+
    • Firefox 67+
    • Opera 51+
    • Safari 12+

欲了解更多資訊,請查看 升級指南

社群

六年前,我們向公眾發布了 Next.js。我們的目標是打造一個零配置的 React 框架,簡化開發者體驗。回顧過去,看到社群的成長以及我們共同實現的成果,實在令人驚嘆。讓我們繼續前進。

Next.js 是 超過 2,400 位獨立開發者、Google 和 Meta 等產業夥伴,以及我們核心團隊共同努力的成果。每週超過 300 萬次 npm 下載量和 94,000 個 GitHub 星標,使 Next.js 成為構建網路的最熱門方式之一。

特別感謝 Google Chrome 的 Aurora 團隊,他們協助進行了基礎研究和實驗,促成了此版本的發布。

此版本由以下貢獻者共同實現:@ijjk, @huozhi, @HaNdTriX, @iKethavel, @timneutkens, @shuding, @rishabhpoddar, @hanneslund, @balazsorban44, @devknoll, @anthonyshew, @TomerAberbach, @philippbosch, @styfle, @mauriciomutte, @hayitsdavid, @abdennor, @Kikobeats, @cjdunteman, @Mr-Afonso, @kdy1, @jaril, @abdallah-nour, @North15, @feedthejim, @brunocrosier, @Schniz, @sedlukha, @hashlash, @Ethan-Arrowood, @fireairforce, @migueloller, @leerob, @janicklas-ralph, @Trystanr, @atilafassina, @nramkissoon, @kasperadk, @valcosmos, @henriqueholtz, @nip10, @jesstelford, @lorensr, @AviAvinav, @SukkaW, @jaycedotbin, @saurabhburade, @notrab, @kwonoj, @sanruiz, @angeloashmore, @falsepopsky, @fmontes, @Gebov, @UltiRequiem, @p13lgst, @Simek, @mrkldshv, @thomasballinger, @kyliau, @AdarshKonchady, @endymion1818, @pedro757, @perkinsjr, @gnoff, @jridgewell, @silvioprog, @mabels, @nialexsan, @feugy, @jackromo888, @crazyurus, @EarlGeorge, @MariaSolOs, @lforst, @maximbaz, @maxam2017, @teobler, @Nutlope, @sunwoo0706, @WestonThayer, @Brooooooklyn, @Nsttt, @charlypoly, @aprendendofelipe, @sviridoff, @jackton1, @nuta, @Rpaudel379, @marcialca, @MarDi66, @ismaelrumzan, @javivelasco, @eltociear, 和 @hiro0218。