跳至內容
返回部落格

2024 年 10 月 15 日,星期二

Next.js 15 RC 2

發佈者

繼五月份首次發佈 Next.js 15 發行候選版本 之後,我們根據您的回饋準備了第二個發行候選版本。以下是我們一直在努力的方向:

立即試用 Next.js 15 發行候選版本 (RC2)

# Use the new automated upgrade CLI
npx @next/codemod@canary upgrade rc
 
# ...or upgrade manually
npm install next@rc react@rc react-dom@rc

注意事項:此候選版本包含先前 RC 的所有變更。先前的 RC

使用程式碼修改 CLI 順暢升級

我們在每個 Next.js 主要版本中都包含程式碼修改(自動程式碼轉換),以協助自動化升級重大變更。

為了使升級更加順暢,我們發佈了增強的程式碼修改 CLI。

npx @next/codemod@canary upgrade rc

此工具可協助您將程式碼庫升級到最新的穩定版或預發佈版本。CLI 將更新您的相依性,顯示可用的程式碼修改,並引導您應用它們。命令列上指定的 dist 標籤(`@rc`、`@canary` 等)決定要升級到的版本。

深入瞭解 Next.js 程式碼修改

用於開發的 Turbopack

用於本地開發的 Turbopack 將在 Next.js 15 正式版中穩定下來,同時保持選用狀態。您可以立即透過執行以下命令來試用它:

next dev --turbo

感謝數千名開發人員參與測試、回報問題並驗證 Turbopack Beta 版和候選版本階段的修復,我們已解決了自第一個 Next.js 15 候選版本以來的 54 個 GitHub 問題。除了社群的努力之外,我們在 vercel.comv0.devnextjs.org 上的內部測試也幫助我們發現了許多額外的改進。

在過去的三個月中,我們一直專注於優化冷編譯效能。與先前的版本相比,我們發現:

  • 記憶體用量減少 25–35%
  • 具有數千個模組的大型頁面的編譯速度提升 30–50%

我們將在未來的版本中持續優化這些方面。

展望未來,Turbopack 團隊在持續快取、減少記憶體使用量以及用於 next build 的 Turbopack 方面取得了顯著進展 — 96% 的測試已通過

注意:請參閱 Turbopack 的所有已支援和未支援的功能

非同步請求 API(重大變更)

在傳統的伺器端渲染中,伺服器會在渲染任何內容之前等待請求。然而,並非所有元件都依賴於請求的特定資料,因此不必等待請求來渲染它們。理想情況下,伺服器應在請求到達之前盡可能做好準備。為了實現這一點,並為未來的優化奠定基礎,我們需要知道何時等待請求。

因此,我們正在將依賴於請求特定資料的 API(例如 headerscookiesparamssearchParams)轉換為**非同步**。

import { cookies } from 'next/headers';
 
export async function AdminPanel() {
  const cookieStore = await cookies();
  const token = cookieStore.get('token');
 
  // ...
}

這是一個**重大變更**,會影響以下 API:

  • cookies
  • headers
  • draftMode
  • layout.jspage.jsroute.jsdefault.jsgenerateMetadatagenerateViewport 中的 params
  • page.js 中的 searchParams

為了更容易遷移,這些 API 可以暫時以同步方式存取,但在下一個主要版本之前,在開發和生產環境中都會顯示警告。我們提供了一個程式碼修改器來自動化遷移。

npx @next/codemod@canary next-async-request-api .

如果程式碼修改器無法完全遷移您的程式碼,請閱讀升級指南。我們還提供了一個範例,說明如何將 Next.js 應用程式遷移到新的 API。

增強伺服器動作的安全性

伺服器動作是可以從客戶端呼叫的伺服器端函式。它們是透過在檔案頂部新增 'use server' 指令並匯出非同步函式來定義的。

即使伺服器動作或工具函式未在程式碼的其他地方匯入,它仍然是一個可公開存取的 HTTP 端點。雖然這種行為在技術上是正確的,但它可能會導致無意中暴露此類函式。

為了提高安全性,我們引入了以下增強功能:

  • 無用程式碼移除:未使用的伺服器動作的 ID 不會暴露給用戶端 JavaScript 軟體包,從而減少軟體包大小並提高效能。
  • 安全的動作 ID:Next.js 現在會建立無法猜測、非確定性的 ID,以允許用戶端引用和呼叫伺服器動作。為了增強安全性,這些 ID 會在每次建置之間定期重新計算。
// app/actions.js
'use server';
 
// This action **is** used in our application, so Next.js
// will create a secure ID to allow the client to reference
// and call the Server Action.
export async function updateUserAction(formData) {}
 
// This action **is not** used in our application, so Next.js
// will automatically remove this code during `next build`
// and will not create a public endpoint.
export async function deleteUserAction(formData) {}

您仍然應該將伺服器動作視為公開的 HTTP 端點。進一步了解保護伺服器動作的安全

靜態路由指示器

Next.js 現在在開發過程中會顯示靜態路由指示器,以協助您識別哪些路由是靜態的或動態的。此視覺提示讓您可以更輕鬆地透過了解頁面的呈現方式來最佳化效能。

您也可以使用 next build 輸出來查看所有路由的呈現策略。

此更新是我們持續努力增強 Next.js 可觀察性的一部分,讓開發人員更容易監控、除錯和最佳化他們的應用程式。我們也正在開發專用的開發人員工具,更多細節即將推出。

進一步了解靜態路由指示器,它可以被停用。

<Form> 元件

新的 <Form> 元件使用預取用戶端導航和漸進式增強功能,擴展了 HTML <form> 元素。

它適用於導航到新頁面的表單,例如導向結果頁面的搜尋表單。

import Form from 'next/form';
 
export default function Page() {
  return (
    <Form action="/search">
      <input name="query" />
      <button type="submit">Submit</button>
    </Form>
  );
}

<Form> 元件具有以下功能:

  • 預取:當表單在視圖中時,會預取 佈局載入中 的 UI,使導航速度更快。
  • 用戶端導航:提交時,共享佈局和用戶端狀態會被保留。
  • 漸進式增強:如果 JavaScript 尚未載入,表單仍然可以透過整頁導航運作。

以前,要實現這些功能需要大量的手動樣板程式碼。例如:

範例
// Note: This is abbreviated for demonstration purposes.
// Not recommended for use in production code.
 
'use client'
 
import { useEffect } from 'react'
import { useRouter } from 'next/navigation'
 
export default function Form(props) {
  const action = props.action
  const router = useRouter()
 
  useEffect(() => {
    // if form target is a URL, prefetch it
    if (typeof action === 'string') {
      router.prefetch(action)
    }
  }, [action, router])
 
  function onSubmit(event) {
    event.preventDefault()
 
    // grab all of the form fields and trigger a `router.push` with the data URL encoded
    const formData = new FormData(event.currentTarget)
    const data = new URLSearchParams()
 
    for (const [name, value] of formData) {
      data.append(name, value as string)
    }
 
    router.push(`${action}?${data.toString()}`)
  }
 
  if (typeof action === 'string') {
    return <form onSubmit={onSubmit} {...props} />
  }
 
  return <form {...props} />
}

進一步了解 <Form> 元件

支援 next.config.ts

Next.js 現在支援 TypeScript 的 next.config.ts 檔案類型,並提供 NextConfig 類型以獲得自動完成和類型安全的選項。

import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  /* config options here */
};
 
export default nextConfig;

深入了解 Next.js 中的 TypeScript 支援

instrumentation.js(穩定版)

instrumentation 檔案及其 register() API 允許使用者介入 Next.js 伺服器生命週期,以監控效能、追蹤錯誤來源,並與 OpenTelemetry 等可觀察性函式庫深度整合。

此功能現在已穩定,可以移除 experimental.instrumentationHook 設定選項。

此外,我們還與 Sentry 合作設計了一個新的 onRequestError 鉤子,可用於

  • 捕捉伺服器上所有拋出錯誤的重要上下文,包括
    • 路由器:頁面路由器或應用程式路由器
    • 伺服器上下文:伺服器元件、伺服器動作、路由處理程式或中介軟體
  • 將錯誤回報給你偏好的可觀察性供應商。
export async function onRequestError(err, request, context) {
  await fetch('https://...', {
    method: 'POST',
    body: JSON.stringify({ message: err.message, request, context }),
    headers: { 'Content-Type': 'application/json' },
  });
}
 
export async function register() {
  // init your favorite observability provider SDK
}

深入了解 onRequestError 函式

開發和建置改進

伺服器元件熱模組替換 (HMR) 伺服器組件 HMR 快取

更快的應用程式路由器靜態生成

我們已最佳化靜態生成以縮短建置時間,尤其針對具有緩慢網路請求的頁面。

先前,我們的靜態最佳化流程會將頁面渲染兩次——一次是為客戶端導覽生成數據,第二次是為初始頁面訪問渲染 HTML。現在,我們會重複使用第一次渲染,省去第二次傳遞,從而減少工作負載和建置時間。

此外,靜態生成工作器現在會跨頁面共用 fetch 快取。如果 fetch 呼叫未選擇停用快取,則其結果會被同一個工作器處理的其他頁面重複使用。這減少了對相同數據的請求次數。

進階靜態生成控制(實驗性)

我們已新增實驗性支援,以便更好地控制靜態生成流程,以適用於受益於更精細控制的進階使用案例。

除非您有特定需求,否則我們建議您繼續使用目前的預設值,因為這些選項可能會導致資源使用量增加,並由於並行性增加而可能導致記憶體不足錯誤。

const nextConfig = {
  experimental: {
	  // how many times Next.js will retry failed page generation attempts
	  // before failing the build
    staticGenerationRetryCount: 1
    // how many pages will be processed per worker
    staticGenerationMaxConcurrency: 8
    // the minimum number of pages before spinning up a new export worker
    staticGenerationMinPagesPerWorker: 25
  },
}
 
export default nextConfig;

深入瞭解靜態生成選項

自行託管的改進

自行託管應用程式時,您可能需要更好地控制 Cache-Control 指令。

一個常見的案例是控制為 ISR 頁面傳送的 stale-while-revalidate 期間。我們已實作了兩項改進

  1. 您現在可以在 next.config 中設定 expireTime 值。這先前是 experimental.swrDelta 選項。
  2. 將預設值更新為一年,確保大多數 CDN 可以完全按預期套用 stale-while-revalidate 語義。

我們也不再使用我們的預設值覆蓋自訂 Cache-Control 值,允許完全控制並確保與任何 CDN 設定的相容性。

最後,我們改進了自行託管時的影像最佳化。先前,我們建議您安裝 sharp 以在您的 Next.js 伺服器上最佳化影像。有時會忽略此建議。使用 Next.js 15,您不再需要手動安裝 sharp — Next.js 在使用 next start 或以獨立輸出模式執行時會自動使用 sharp

想了解更多,請參閱我們關於自行託管 Next.js 的全新示範和教學影片

支援 ESLint 9

隨著 ESLint 8 於 2024 年 10 月 5 日終止服務,Next.js 15 也引入了對 ESLint 9 的支援。

為了確保順利過渡,Next.js 保持向下相容,這意味著您可以繼續使用 ESLint 8 或 9。

如果您升級到 ESLint 9,並且我們偵測到您尚未採用新的設定格式,Next.js 將自動套用 ESLINT_USE_FLAT_CONFIG=false 的相容措施來簡化遷移過程。

此外,在執行 next lint 時,將會移除已棄用的選項,例如 —ext—ignore-path。請注意,ESLint 最終將在 ESLint 10 中禁止這些較舊的設定,因此我們建議您盡快開始遷移。

有關這些變更的更多詳細資訊,請查看遷移指南

作為此更新的一部分,我們還將 eslint-plugin-react-hooks 升級到 v5.0.0,其中引入了關於 React Hooks 使用的新規則。您可以在 eslint-plugin-react-hooks@5.0.0 的更新日誌 中查看所有變更。

其他變更

  • RC 1 部落格文章中先前描述的所有變更
  • [重大變更] 我們已棄用在 App Router 中匯出 export const runtime = "experimental-edge" 的做法。現在使用者應改用 export const runtime = "edge"。我們已新增一個程式碼修改器來執行此操作(PR
  • [重大變更] 在渲染期間呼叫 revalidateTagrevalidatePath 現在會拋出錯誤(PR
  • [重大變更] instrumentation.jsmiddleware.js 檔案現在將使用供應商提供的 React 套件(PR
  • [重大變更] 最低 Node.js 版本需求已更新至 18.18.0(PR
  • [重大變更] next/dynamic:已移除棄用的 suspense 屬性,且當元件在 App Router 中使用時,將不再插入空的 Suspense 邊界(PR
  • [重大變更] 在 Edge Runtime 上解析模組時,將不會套用 worker 模組條件(PR
  • [重大變更] 禁止在伺服器元件中搭配 next/dynamic 使用 ssr: false 選項(PR
  • [改進] outputFileTracingRootoutputFileTracingIncludesoutputFileTracingExcludes 已從實驗階段升級為穩定版(PR
  • 【改進】避免將全域 CSS 檔案與樹狀結構更深層的 CSS 模組檔案合併 (PR)
  • 【改進】現在可以透過 NEXT_CACHE_HANDLER_PATH 環境變數指定快取處理程式 (PR)
  • 【改進】頁面路由器現在同時支援 React 18 和 React 19 (PR)
  • 【改進】如果啟用了偵錯器,錯誤覆蓋層現在會顯示一個按鈕來複製 Node.js 偵錯器網址 (PR)
  • 【改進】應用程式路由器上的客戶端預取現在使用 priority 屬性 (PR)
  • 【改進】Next.js 現在提供了一個 unstable_rethrow 函式,可以在應用程式路由器中重新拋出 Next.js 內部錯誤 (PR)
  • 【改進】unstable_after 現在可以在靜態頁面中使用 (PR)
  • 【改進】如果在伺服器端渲染 (SSR) 期間使用了 next/dynamic 元件,則會預取區塊 (PR)
  • [改善] 應用程式路由器現在支援 esmExternals 選項(PR
  • [改善] 現在可以使用 experimental.allowDevelopmentBuild 選項,允許在使用 next build 時設定 NODE_ENV=development 以進行除錯(PR
  • [改善] 現在已在頁面路由器中停用伺服器動作轉換(PR
  • [改善] 建置工作器現在會在它們退出時停止建置程序,避免卡住(PR
  • [改善] 從伺服器動作重新導向時,重新驗證現在將正確套用(PR
  • [改善] 現在可以正確處理 Edge Runtime 上平行路由的動態參數(PR
  • [改善] 靜態頁面現在將在初始載入後遵守 staleTime(PR
  • [改善] 更新了 vercel/og,修復了記憶體洩漏問題(PR
  • [改善] 更新了修補程式碼的時機,允許使用 msw 等套件來模擬 API(PR

貢獻者

Next.js 是超過 3,000 位個別開發者和我們 Vercel 核心團隊共同努力的成果。本次發佈由以下人員完成:

非常感謝 @huozhi、@shuding、@wyattjoh、@PaulAsjes、@mcnaveen、@timneutkens、@stipsan、@aktoriukas、@sirTangale、@greatvivek11、@sokra、@anatoliik-lyft、@wbinnssmith、@coltonehrman、@hungdoansy、@kxlow、@ztanner、@manovotny、@leerob、@ryota-murakami、@ijjk、@pnutmath、@feugy、@Jeffrey-Zutt、@wiesson、@eps1lon、@devjiwonchoi、@Ethan-Arrowood、@kenji-webdev、@domdomegg、@samcx、@Jaaneek、@evanwinter、@kdy1、@balazsorban44、@feedthejim、@ForsakenHarmony、@kwonoj、@delbaoliveira、@xiaohanyu、@dvoytenko、@bobaaaaa、@bgw、@gaspar09、@souporserious、@unflxw、@kiner-tang、@Ehren12、@EffectDoplera、@IAmKushagraSharma、@Auxdible、@sean-rallycry、@jeanmax1me、@unstubbable、@NilsJacobsen、@adiguno、@ryan-nauman、@zsh77、@KagamiChan、@steveluscher、@MehfoozurRehman、@vkryachko、@chentsulin、@samijaber、@begalinsaf、@FluxCapacitor2、@lukahartwig、@brianshano、@pavelglac、@styfle、@symant233、@HristovCodes、@karlhorky、@jonluca、@jonathan-ingram、@mknichel、@sopranopillow、@Gomah、@imddc、@notrab、@gabrielrolfsen、@remorses、@AbhiShake1、@agadzik、@rishabhpoddar、@rezamauliadi、@IncognitoTGT、@webtinax、@BunsDev、@nisabmohd、@z0n、@bennettdams、@joeshub、@n1ckoates、@srkirkland、@RiskyMH、@coopbri、@okoyecharles、@diogocapela、@dnhn、@typeofweb、@davidsa03、@imranolas、@lubieowoce、@maxhaomh、@mirasayon、@blvdmitry、@hwangstar156、@lforst、@emmerich、@christian-bromann、@Lsnsh、@datner、@hiro0218、@flybayer、@ianmacartney、@ypessoa、@ryohidaka、@icyJoseph、@Arinji2、@lovell、@nsams、@Nayeem-XTREME、@JamBalaya56562、@Arindam200、@gaojude、@qqww08、@todor0v、@tokkiyaa、@arlyon、@lorensr、@Juneezee、@Sayakie、@IGassmann、@bosconian-dynamics、@phryneas、@akazwz、@atik-persei、@shubh73、@alpedia0、@chogyejin、@notomo、@ArnoldVanN、@dhruv-kaushik、@kevva、@Kahitar、@anay-208、@boris-szl、@devnyxie、@LorisSigrist、@M-YasirGhaffar、@Lada496、@kippmr、@torresgol10、@pkiv、@Netail、@jontewks、@ArnaudFavier、@chrisjstott、@mratlamwala、@mayank1513、@karlkeefer、@kshehadeh、@Marukome0743、@a89529294、@anku255、@KeisukeNagakawa、@andrii-bodnar、@aldosch、@versecafe、@steadily-worked、@cfrank、@QiuranHu、@farsabbutt、@joostmeijles、@saltcod、@archanaagivale30、@crutchcorn、@crebelskydico、@Maaz-Ahmed007、@jophy-ye、@remcohaszing、@JoshuaKGoldberg、@creativoma、@GyoHeon、@SukkaW、@MaxLeiter、@neila-a、@stylessh、@Teddir、@ManuLpz4、@Julian-Louis、@syi0808、@mert-duzgun、@amannn、@MonstraG、@hamirmahal、@tariknh、@Kikobeats、@LichuAcu、@Kuboczoch、@himself65、@Sam-Phillemon9493、@Shruthireddy04、@Hemanshu-Upadhyay、@timfuhrmann、@controversial、@pathliving、@mischnic、@mauroaccornero、@NavidNourani、@allanchau、@ekremkenter、@yurivangeffen、@gnoff、@darthmaim、@gdborton、@Willem-Jaap、@KentoMoriwaki、@TrevorSayre、@marlier、@Luluno01、@xixixao、@domin-mnd、@niketchandivade、@N2D4、@kjugi、@luciancah、@mud-ali、@codeSTACKr、@luojiyin1987、@mehmetozguldev、@ronanru、@tknickman、@joelhooks、@khawajaJunaid、@rubyisrust、@abdull-haseeb、@bewinsnw、@housseindjirdeh、@li-jia-nan、@aralroca、@s-ekai、@ah100101、@jantimon、@jordienr、@iscekic、@Strift、@slimbde、@nauvalazhar、@HughHzyb、@guisehn、@wesbos、@OlyaPolya、@paarthmadan、@AhmedBaset、@dineshh-m、@avdeev、@Bhavya031、@MildTomato、@Bjornnyborg、@amikofalvy、@yosefbeder、@kjac、@woutvanderploeg、@Ocheretovich、@ProchaLu、@luismiramirez、@omahs、@theoludwig、@abhi12299、@sommeeeer、@lumirlumir、@royalfig、@iampoul、@molebox、@txxxxc、@zce、@mamuso、@kahlstrm、@vercel-release-bot、@zhawtof、@PapatMayuri、@PlagueFPS、@IDNK2203、@jericopulvera、@liby、@CannonLock、@timfish、@whatisagi、@none23、@haouvw、@Pyr33x、@SouthLink、@frydj、@CrutchTheClutch、@sleevezip、@r34son、@yunsii、@md-rejoyan-islam、@kartheesan05、@nattui、@KonkenBonken、@weicheng95、@brekk、@Francoscopic、@B33fb0n3、@ImDR、@nurullah、@hdodov、@ebCrypto、@soedirgo、@floriangosse、@Tim-Zj、@raeyoung-kim、@erwannbst、@DerTimonius、@hirotomoyamada、@Develliot、@chandanpasunoori、@vicb、@ankur-dwivedi、@kidonng、@baeharam、@AnaTofuZ、@coderfin、@xugetsu、@alessiomaffeis、@kutsan、@jordyfontoura、@sebmarkbage、@tranvanhieu01012002、@jlbovenzo、@Luk-z、@jaredhan418、@bangseongbeom、@penicillin0、@neoFinch、@DeepakBalaraman、@Manoj-M-S、@Unsleeping、@lonr、@Aerilym、@ytori、@acdlite、@actopas、@n-ii-ma、@adcichowski、@mobeigi、@JohnGemstone 與 @jjm2317 的協助!