跳到內容
返回部落格

2024年12月10日,星期二

Next.js 15.1

發布者

Next.js 15.1 帶來了核心升級、全新 API 以及開發者體驗的改進。主要更新包括

立即升級,或開始使用

終端機
# Use the automated upgrade CLI
npx @next/codemod@canary upgrade latest
 
# ...or upgrade manually
npm install next@latest react@latest react-dom@latest
 
# ...or start a new project
npx create-next-app@latest

React 19 (穩定版)

Next.js 15.1 現在完全支援 React 19

  • 對於 Pages Router:您現在可以使用 React 19 穩定版,而無需 Release Candidate 或 Canary 版本,同時繼續支援 React 18。
  • 對於 App Router:我們將繼續內建提供 React Canary 版本。這些版本包含所有 React 19 穩定版的變更,以及在新的 React 版本發布之前,於框架中驗證的較新功能。

自 Next.js 15 版本發布以來,React 19 的一項重大新增功能是「sibling pre-warming」。

如需 React 19 更新的完整概述,請參閱官方 React 19 部落格文章

改善錯誤除錯

我們改善了 Next.js 中的錯誤除錯功能,確保您可以快速找到問題的根源,無論問題出現在終端機、瀏覽器或附加的除錯工具中。這些增強功能適用於 Webpack 和 Turbopack(現在 Next.js 15 版本中已穩定)。

原始碼地圖增強功能

現在透過原始碼地圖的改進使用,可以更輕鬆地將錯誤追溯到其來源。我們實作了原始碼地圖的 ignoreList 屬性,這讓 Next.js 可以隱藏外部依賴項的堆疊框架,讓您的應用程式程式碼成為主要焦點。

為了更精準地對應方法名稱的原始碼,我們建議採用 Turbopack(現在已穩定),與 Webpack 相比,它在處理和偵測原始碼地圖方面有所改進。

對於函式庫作者:我們建議在發布函式庫時,在原始碼地圖中填入 ignoreList 屬性,特別是當它們被設定為外部時(例如在 serverExternalPackages 設定中)。

摺疊堆疊框架

我們改進了摺疊堆疊框架的邏輯,以突顯程式碼中最相關的部分。

  • 在瀏覽器和錯誤覆蓋層中:來自第三方依賴項的堆疊框架預設為隱藏,重點放在您的應用程式程式碼上。您可以點擊開發人員工具或覆蓋層中的「顯示忽略的框架」來顯示隱藏的框架。
  • 在終端機中:第三方依賴項框架也預設為摺疊,且錯誤格式化現在與瀏覽器輸出一致,以提供一致的除錯體驗。錯誤會在瀏覽器中重新播放,以確保在您需要完整堆疊追蹤時,不會在開發期間錯過重要資訊。

增強效能分析

內建的瀏覽器效能分析工具也能識別忽略的堆疊框架。這讓應用程式的效能分析更加容易,讓您可以精確找出程式碼中的慢速函式,而不會受到外部函式庫的干擾。

透過 Edge Runtime 改善

使用 Edge Runtime 時,錯誤現在會在開發環境中一致地顯示,確保無縫的除錯體驗。先前,記錄的錯誤只會包含訊息,而不會包含堆疊。

之前與之後

終端機之前

終端機
  app/page.tsx (6:11) @ eval
  Error: boom
    at eval (./app/page.tsx:12:15)
    at Page (./app/page.tsx:11:74)
    at AsyncLocalStorage.run (node:async_hooks:346:14)
    at stringify (<anonymous>)
    at AsyncLocalStorage.run (node:async_hooks:346:14)
    at AsyncResource.runInAsyncScope (node:async_hooks:206:9)
digest: "380744807"
  4 | export default function Page() {
  5 |   const throwError = myCallback(() => {
> 6 |     throw new Error('boom')
    |           ^
  7 |   }, [])
  8 |
  9 |   throwError()
 GET / 500 in 2354ms

終端機之後

終端機
   Error: boom
    at eval (app/page.tsx:6:10)
    at Page (app/page.tsx:5:32)
  4 | export default function Page() {
  5 |   const throwError = myCallback(() => {
> 6 |     throw new Error('boom')
    |          ^
  7 |   }, [])
  8 |
  9 |   throwError() {
  digest: '225828171'
}

錯誤覆蓋層之前

An example of the Next.js error overlay before version 15.1
版本 15.1 之前的 Next.js 錯誤覆蓋層範例

錯誤覆蓋層之後

An example of the Next.js error overlay after version 15.1
版本 15.1 之後的 Next.js 錯誤覆蓋層範例

這些改進使錯誤更清晰、更直觀,讓您可以將時間集中在建置應用程式,而不是除錯。

我們也很高興宣布即將在未來版本中推出重新設計的錯誤覆蓋層 UI。

after (穩定版)

after() API 在 Next.js 15 RC 的第一個版本中推出後,現在已穩定。

after() 提供一種方法,可以在回應完成串流傳輸到使用者後,執行記錄、分析和其他系統同步等工作,而不會阻礙主要回應。

主要變更

自推出以來,我們已將 after() 穩定化,並解決了包括下列項目的意見回饋

  • 改善對自架設 Next.js 伺服器的支援。
  • 針對 after() 與其他 Next.js 功能互動的情境進行錯誤修正
  • 增強可擴充性,讓其他平台能夠注入自己的 waitUntil() 原語來支援 after()
  • 支援 Server Actions 和 Route Handlers 中的執行階段 API,例如 cookies()headers()
app/layout.js
import { after } from 'next/server';
import { log } from '@/app/utils';
 
export default function Layout({ children }) {
  // Secondary task
  after(() => {
    log();
  });
 
  // Primary task
  return <>{children}</>;
}

閱讀文件以深入瞭解 after API 以及如何在文件中加以運用。

forbiddenunauthorized (實驗性)

Next.js 15.1 包含兩個實驗性 API:forbidden()unauthorized(),它們是以社群意見回饋為基礎而建立。

我們很樂意收到您的意見回饋 — 請在您的開發環境中試用,並在這個討論串中分享您的想法。

概觀

如果您熟悉 App Router,您可能已使用過 notFound() 來觸發 404 行為,以及可自訂的 not-found.tsx 檔案。在版本 15.1 中,我們將此方法擴展到授權錯誤

forbidden() 透過 forbidden.tsx 觸發 403 錯誤,並提供可自訂的 UI。

unauthorized() 透過 unauthorized.tsx 觸發 401 錯誤,並提供可自訂的 UI。

須知:notFound() 錯誤一樣,如果錯誤是在初始回應標頭傳送後觸發,則狀態碼將為 200深入瞭解

啟用功能

由於此功能仍為實驗性,因此您需要在 next.config.ts 檔案中啟用它

next.config.ts
import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  experimental: {
    authInterrupts: true,
  },
};
 
export default nextConfig;

注意: Next.js 15 中引入了 next.config.ts 支援。深入瞭解

使用 forbidden()unauthorized()

您可以在伺服器動作、伺服器元件、用戶端元件或路由處理器中使用 forbidden()unauthorized()。以下範例

import { verifySession } from '@/app/lib/dal';
import { forbidden } from 'next/navigation';
 
export default async function AdminPage() {
  const session = await verifySession();
 
  // Check if the user has the 'admin' role
  if (session.role !== 'admin') {
    forbidden();
  }
 
  // Render the admin page for authorized users
  return <h1>Admin Page</h1>;
}

建立自訂錯誤頁面

若要自訂錯誤頁面,請建立下列檔案

app/forbidden.tsx
import Link from 'next/link';
 
export default function Forbidden() {
  return (
    <div>
      <h2>Forbidden</h2>
      <p>You are not authorized to access this resource.</p>
      <Link href="/">Return Home</Link>
    </div>
  );
}
app/unauthorized.tsx
import Link from 'next/link';
 
export default function Unauthorized() {
  return (
    <div>
      <h2>Unauthorized</h2>
      <p>Please log in to access this page.</p>
      <Link href="/login">Go to Login</Link>
    </div>
  );
}

我們要感謝 Clerk 透過 PR 提出此功能,並協助我們建立 API 原型。在我們於 15.2 版本中將此功能穩定化之前,我們計畫為 API 新增更多功能和改進,以支援更廣泛的使用案例。

請閱讀 unauthorizedforbidden API 的文件,以取得更多詳細資訊。

其他變更

  • [功能]create-next-app 中使用 ESLint 9 (PR)
  • [功能] 將最大快取標籤增加到 128 個 (PR)
  • [功能] 新增選項以停用實驗性 CssChunkingPlugin (PR)
  • [功能] 新增實驗性 CSS 內嵌支援 (PR)
  • [改進] 靜止 Sass legacy-js-api 警告 (PR)
  • [改進] 修正使用 rewrites 時未處理的拒絕 (PR)
  • [改進] 確保在 webpack worker 失敗時父程序結束 (PR)
  • [改進] 修正 catch-all 路由上的路由攔截 (PR)
  • [改進] 修正在請求去重複化中的回應複製問題 (PR)
  • [改進] 修正多個根版面配置之間的伺服器動作重新導向 (PR)
  • [改進] 支援以字串形式提供 MDX 外掛程式,以實現 Turbopack 相容性 (PR)

貢獻者

Next.js 是超過 3,000 位個別開發人員共同努力的成果。此版本由以下人員為您帶來

非常感謝 @sokra、@molebox、@delbaoliveira、@eps1lon、@wbinnssmith、@JamBalaya56562、@hyungjikim、@adrian-faustino、@mottox2、@lubieowoce、@bgw、@mknichel、@wyattjoh、@huozhi、@kdy1、@mischnic、@ijjk、@icyJoseph、@acdlite、@unstubbable、@gaojude、@devjiwonchoi、@cena-ko、@lforst、@devpla、@samcx、@styfle、@ztanner、@Marukome0743、@timneutkens、@JeremieDoctrine、@ductnn、@karlhorky、@reynaldichernando、@chogyejin、@y-yagi、@philparzer、@alfawal、@Rhynden、@arlyon、@MJez29、@Goodosky、@themattmayfield、@tobySolutions、@kevinmitch14、@leerob、@emmanuelgautier、@mrhrifat、@lid0a、@boar-is、@nisabmohd、@PapatMayuri、@ovogmap、@Reflex2468、@LioRael、@betterthanhajin、@HerringtonDarkholme、@bpb54321、@ahmoin、@Kikobeats、@abdelrahmanAbouelkheir、@lumirlumir、@yeeed711、@petter 和 @suu3 的協助!