Next.js 在約 2022 年年底發布了 App Router,剛推出時其實爭議不小,當時 Bug 較多且 Performance 問題也時有所聞。當然,Vercel 團隊這兩年來也不斷努力,將 App Router 的功能修補得更完善、更穩定。
經過兩年的觀察與評估,我們認為 App Router 的生態系已經相當成熟。因此,因創科技在今年年初開始正式導入,目前新的專案也全面採用 App Router 進行開發。
這篇文章將介紹 App Router 的關鍵新功能與架構改變,並分享一些我們在實際開發中的經驗供大家參考。
1. 檔案架構改變
App Router 改變最大的莫過於檔案架構與路由邏輯:
- /pages to /app 原本 Pages Router 的頁面檔案都放在 /pages 目錄下,而 App Router 則統一移至 /app 目錄下。這不僅是路徑的改變,更代表了底層渲染邏輯的區隔。
- 動態路由 (Dynamic Routes) 在 Pages Router 中,動態路由直接寫在檔案名稱上,例如 [slugs].tsx (或是 [...slugs].tsx)。但在 App Router 中,路由必須由資料夾 (Folder) 來定義,實際的頁面內容則統一命名為 page.tsx。
範例: /app/blog/[slug]/page.tsx
- 特殊檔案約定 (Special Files) App Router 除了 page.tsx 之外,還加上了許多功能性的特殊檔案名稱,例如 loading.tsx (處理載入狀態)、error.tsx (處理錯誤) 以及 not-found.tsx,讓開發者能更直觀地處理各種 UI 狀態。
- _app.tsx to layout.tsx 原本的全域入口 _app.tsx 被 layout.tsx 取代。App Router 也支援 Nested Layouts,每個資料夾層級都可以有自己的 layout.tsx,子目錄會自動繼承父層的 Layout,大幅減少了重複程式碼的撰寫,也解決了過去在換頁時 Layout 狀態難以保留的問題。
2. 快取與資料獲取機制 (Caching & Data Fetching)
App Router 的快取機制與過去截然不同,提供了更細更其強大的控制:
在舊版 Pages Router,我們只能在頁面層級設定 revalidate 參數(ISR),或是透過 API 手動清除快取。
新版 App Router 則是基於 Web Standard 的 fetch API 進行擴充。除了原本的 revalidate 時間設定外,我們現在可以針對每一個 API 請求設定快取標籤 (Tags)。這讓我們能透過 revalidateTag 精準地清除特定資料的快取,而不需要重建整個頁面,大幅提升了資料更新的效率與彈性。
// 快取設定範例:每小時(3600 秒清除快取), 加上 posts tag
fetch('https://...', { next: { revalidate: 3600, tags: ['posts'] } })//清除所有有用到 posts tag 的頁面
revalidateTag('posts', "max");**小心踩雷**
- 如果你在頁面有定義 revalidate 參數,而這個頁面又有元件需要使用 fetch 抓資料(架設也有使用 revalidate),那這個頁面的快取會以最小的參數為主。eg. 假設頁面的 revalidate 參數為 3600 * 24 (一天),而 fetch 的 revalidate 為 3600,則這個頁面一樣會每小時重新 render 一次。
- 如果頁面使用的 fetch 沒有設定 revalidate 或是 revalidate 設定為 0,那這個頁面會完全不被快取,而是每次都是重新 Dynamic Render。
3. Client & Server Components
這是一個非常重大的觀念轉變。App Router 全面支援 React Server Components (RSC)。
簡單來說,在 App Router 中,所有的 Component 預設都是 Server Component,這意味著它們只會在伺服器端執行渲染,不會被打包到前端的 JavaScript Bundle 中。只有當你在檔案頂端加上 "use client" 指令時,該元件才會變成 Client Component(類似過去我們熟悉的 React 元件)。
為什麼要這樣分?主要有三個好處:
- 前端 Payload 變小: 因為 Server Component 的邏輯與依賴套件不會被傳送到瀏覽器,使用者的下載量變少,網站載入速度顯著提升。
- 更高的安全性: Server Component 可以直接在元件內安全地讀取資料庫或使用 API Key,而不必擔心機密資訊洩漏到前端。
- Server Actions: 我們可以直接在 Component 內撰寫 Server Functions 來處理表單送出 (Form Actions) 或資料篩選。這讓我們在很多簡單的場景下,不再需要額外撰寫 API Route (/api/...),簡化了前後端的溝通成本。
結論
新的技術一定會帶來新的學習曲線與改變,相反地,也有可能將大家習慣的一些舊功能移除。對我們來說,App Router 確實讓開發變得更有彈性且功能強大,但也並非沒有痛點(例如:原本支援的 root domain locale 功能被移除,雖然可透過 Middleware 解決,但稍微增加了複雜度)。
總結來說,升級到 App Router 是利大於弊的。
因創科技會持續評估並測試新技術,在確保安全與穩定的前提下,致力於提供客戶不只是最新,更是最「合適」的解決方案。
