📋 目錄
Next.js 的效能優化正在進入新階段。Turbopack 從 beta 到 stable、Async Request APIs 的引入、Caching 預設值的收緊——這些變化不是小事,它們直接影響你怎麼寫 Next.js 應用。對於已經在用 Next.js 的團隊,15 到 16 的升級遷移成本比以往任何一次都高。
前端工程師為什麼要關心 Next.js 15/16
Next.js 是目前最流行的 React Meta-Framework。它的每一次重大升級,都會影響數百萬個應用的架構選擇。
Next.js 15/16 這次的核心主題是:效能基礎設施的現代化。
Turbopack 的穩定化是最大的變化——Webpack 的時代正在 Next.js 裡慢慢結束。同時,Async Request APIs 的引入、Caching 行為的改變,都在要求開發者重新思考「資料怎麼獲取」這個基本問題。
Turbopack:Webpack 的接班人
從 Webpack 到 Turbopack
Next.js 過去使用 Webpack 作為默認的 bundler。Webpack 在過去十年是前端生態系的支柱,但它的 JavaScript 執行環境成為大型專案的效能瓶頸。
Turbopack 是 Vercel 用 Rust 開發的新一代 bundler:
# Next.js 15/16 預設使用 Turbopack
# 不需要在 next.config.js 裡開啟
# 過去(使用 Webpack)
next dev # 慢,cold start 可能 30 秒+
# 現在(Turbopack)
next dev # 快,cold start 通常 3-5 秒
Turbopack 的效能提升:
| 場景 | Webpack | Turbopack |
|---|---|---|
| Cold Start | 30s+ | 3-5s |
| Hot Reload | 1-3s | <100ms |
| 大型 Monorepo | 慢 | 快 |
Turbopack 的限制(過渡期)
目前 Turbopack 在 Next.js 15/16 的支援範圍:
// ✅ Turbopack 支援
next dev // 開發模式
next build // 生產建置(實驗性)
next start // 生產伺服器
// ⚠️ Turbopack 尚未支援
//某些 webpack plugins(如 next-translate)
// 部分 custom webpack 配置
遷移到 Turbopack
如果你的專案有 custom webpack 配置,需要迁移:
// next.config.ts (Next.js 16)
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
// 過去的 webpack 配置
webpack: (config) => {
// 某些需要在 Turbopack 下重新實現
return config;
},
// Turbopack 的實驗性功能
experimental: {
turbo: {
// Turbopack 特定配置
},
},
};
Async Request APIs
什麼是 Async Request APIs
Next.js 15 引入了一套新的非同步請求處理 API,解決了過去 Server Components 處理請求時的一些限制:
// 過去(Synchronous Request APIs)
// app/page.tsx
async function getData() {
// 某些情況下可能會有 race condition
const res = await fetch('https://api.example.com/data');
return res.json();
}
// Next.js 15+(Async Request APIs)
// 使用 cookies(), headers(), params() 的 async 版本
import { cookies, headers } from 'next/headers';
async function getData() {
// Async 版本的 cookies()
const cookieStore = await cookies();
const theme = cookieStore.get('theme');
// Async 版本的 headers()
const headersList = await headers();
const userAgent = headersList.get('user-agent');
}
為什麼需要 Async 版本
// 過去的寫法在某些邊緣情況會有問題
// app/page.tsx
import { cookies } from 'next/headers';
export default function Page() {
// 這個在 Server Components 裡有時候會失敗
const cookieStore = cookies();
const theme = cookieStore.get('theme');
// ⚠️ 這個資料獲取可能在 cookies 還沒准备好時就執行
const data = fetch('https://api.example.com/data');
}
Async Request APIs 讓請求處理的順序更明確,減少 race conditions。
Server Action 安全性更新
過去的問題
Next.js 的 Server Actions 允許在客戶端直接呼叫伺服器端的函式。這個功能很方便,但過去有一些安全性漏洞:
// 過去的 Server Action(安全性問題)
'use server'
// 這個 action 沒有任何防護
async function updateUser(formData: FormData) {
const userId = formData.get('userId');
const newName = formData.get('name');
// ⚠️ 攻擊者可以直接呼叫這個 action
// 只需要知道 action 的路徑
await db.user.update({ id: userId, name: newName });
}
Next.js 15/16 的安全性改進
// Next.js 15+ 的 Server Action
'use server'
// 綁定到特定表單
import { useActionState } from 'react';
async function updateUser(prevState, formData: FormData) {
const userId = formData.get('userId');
const newName = formData.get('name');
// 明確的驗證
if (!userId || typeof userId !== 'string') {
return { error: 'Invalid userId' };
}
await db.user.update({ id: userId, name: newName });
return { success: true };
}
// 在客戶端使用 action 並绑定到 form
import { updateUser } from './actions';
function UserForm() {
const [state, action, pending] = useActionState(updateUser, null);
return (
<form action={action}>
<input name="userId" type="text" />
<input name="name" type="text" />
<button type="submit" disabled={pending}>更新</button>
</form>
);
}
Caching 預設值改變
Next.js 15 的 Caching 變化
Next.js 15 收紧了部分快取行為的預設值:
// fetch() 的快取預設值改變
// Next.js 14: fetch() 預設 cache: 'force-cache'(強制快取)
// Next.js 15: fetch() 預設 cache: 'no-store'(不快取)
// 過去你需要明確指定
const data = await fetch('https://api.example.com/data', {
cache: 'no-store' // 因為預設是快取
});
// 現在如果你想要快取,需要明確指定
const data = await fetch('https://api.example.com/data', {
cache: 'force-cache' // 現在需要明確說要快取
});
升級時的檢查清單
// 如果你的程式碼依賴 fetch 快取行為,需要檢查:
// ❌ 過去依賴 fetch 預設快取
const data = await fetch('https://api.example.com/data');
// ✅ 現在需要明確
const data = await fetch('https://api.example.com/data', {
cache: 'force-cache'
});
// ✅ 或者使用 Next.js 的 unstable_cache
import { unstable_cache } from 'next/cache';
const getCachedData = unstable_cache(
async () => {
const res = await fetch('https://api.example.com/data');
return res.json();
},
['key'], // cache key
{ revalidate: 3600 } // 每小時重新驗證
);
React 19 整合
Next.js 15/16 的 React 19 功能
Next.js 15/16 開始整合 React 19 的新功能:
// React 19 的新 hooks
import { useActionState, useFormStatus } from 'react';
// useActionState:管理 action 的狀態
function SubmitButton() {
const [state, formAction] = useActionState(asyncAction, null);
return <button formAction={formAction}>提交</button>;
}
// useFormStatus:在 form 內的 button 可以知道 form 的狀態
function SubmitButton() {
const { pending } = useFormStatus();
return <button type="submit" disabled={pending}>提交中...</button>;
}
Partial Prerendering
React 19 和 Next.js 15/16 帶來了 Partial Prerendering(PPR)——一種混合靜態和動態內容的方式:
// app/page.tsx
import { Suspense } from 'react';
export default function Page() {
return (
<div>
{/* 靜態部分:build 時渲染 */}
<header>
<h1>我的網站</h1>
</header>
{/* 動態部分:request 時渲染 */}
<Suspense fallback={<ProductSkeleton />}>
<ProductList />
</Suspense>
</div>
);
}
升級檢查清單
立即需要處理的項目
- Caching 預設值:檢查所有
fetch()呼叫,確認快取行為符合預期 - Server Actions:確保有適當的驗證和授權
- Async Request APIs:更新
cookies()、headers()、params()的用法為 async
建議的升級步驟
# 1. 升級到 Next.js 15
npm install next@15
# 2. 執行 Next.js 的 codemod
npx @next/codemod@latest .
# 3. 修復 codemod 無法處理的變更
# 檢查 console 錯誤和 warnings
# 4. 測試所有 Server Actions
# 確認沒有安全漏洞
# 5. 測試 Caching 行為
# 確認資料獲取符合預期
結語:Next.js 的方向越來越明確
Next.js 15/16 的方向很明確:把 React Server Components 的模型做得更完整,把效能基礎設施升級到 Rust。
Turbopack 的到來,結束了 Webpack 在 Next.js 裡的十年主導地位。Async Request APIs 的引入,讓 Server Components 的行為更加可預測。React 19 的整合,带来了新的 DX 工具(useActionState、useFormStatus)。
這次升級的遷移成本比以往高。如果你的專案有大量自定義 webpack 配置或複雜的快取邏輯,升級需要更謹慎的規劃。建議先在 staging 環境測試完整的升級路徑,再決定生產環境的升級時間點。
延伸閱讀
- React Server Actions 最佳實踐 — 伺服器動作詳解
- Vite 8 Rust 統一建置 — 建置工具最新動態
本文是「2026 Meta-Framework 比較」系列文章之一。