---
title: "NEXTJS 13.3.4 昇級踩坑筆記，Server side component 時代來臨 - migrate page route to app route"
description: "記錄 Next.js 13 遷移至 App Route 的完整踩坑筆記，涵蓋 Server Component、新 Data Fetching、meta api 及受影響套件的處理方式。"
canonical_url: "https://blog.markkulab.net/post/nextjs-upgrade-app-route"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/author/mark-ku"
site: "Mark Ku's Blog"
date_published: "2023-05-28 01:01:01 +0800"
category: "Frontend"
tags: ["nextjs", "react", "upgrade", "app route", "server component", "typescript", "frontend"]
language: "zh-TW"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "轉載或引用請註明作者並附上原文連結"
---

# NEXTJS 13.3.4 昇級踩坑筆記，Server side component 時代來臨 - migrate page route to app route

##  前言
為了重寫我們的德國電商網站，我進行了深入評估，並決定採用 Next js 的最新穩定版本13.4.3，這個版本的 SEO meta api和server side component功能具有極高的吸引力，且加上未來許多 NextJS的功能都將以app route 上，因此我們選擇採用app route對我們來說毫無疑問。

## 1 [Server side component](https://nextjs.org/docs/getting-started/react-essentials)

### 1.1 App folder 下的元件或頁面，預設都是 server side component 
* By default, all components on NextJS 13 inside the App folder are server components. And Server Components cannot use client features such as useState, useEffect, etc.

* For now, to use third-party components the solution is to create a wrapper for each client component that doesn't include the directive 'use client':

### 1.2 Server side component 好處
Server Components的運作方式是在伺服器上進行渲染，從而只傳遞需要的JS Bundle程式碼至用戶端瀏覽器，不必要的js則不會被下載，這個特性能有效地減少網路傳輸量，提高效能和速度。

### 1.3限制

不能使用 useState 和 useReducer、 Hooks、useEffect、useLayoutEffect 

### 1.4 如果要使用 clinet side component ，每個 component 都要加上這一行
```
"use client";
import xxx
...
```

## 2 新 useRoute 
```
import { useRouter, useParams, usePathname ,useSearchParams } from 'next/navigation';
```

### 2.1 在新的 useRoute ，並沒有 locale 
```
const { locale } = useRouter(); 
```

## 2.2 路由
### 2.2.1 資料夾結構
這種改動的方式，更直觀從資料夾結構了解是頁面還是元件。

| Url | Page route| App route |
| -------- | -------- | -------- |
| /     | /page/index.tsx     | /app/page.tsx     |
| /about-us     | /page/about-us.tsx     | /app/about-us/page.tsx     |

P.S. 附錄有寫了一個Powershell 快速將 page folder 遷移到 app folder 

### 2.2.2 [api 路由](https://nextjs.org/docs/app/building-your-application/routing/router-handlers)

| Page  | Route 2 | Result 3 |
| -------- | -------- | -------- |
| app/page.js     | app/route.js     | Conflict     |
| app/page.js     | app/api/route.js     | Valid     |
| app/[user]/page.js     | app/api/route.js     | Valid     |

```
app/products/api/route.ts
import { NextResponse } from 'next/server';
 
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const id = searchParams.get('id');
  const res = await fetch(`https://data.mongodb-api.com/product/${id}`, {
    headers: {
      'Content-Type': 'application/json',
      'API-Key': process.env.DATA_API_KEY,
    },
  });
  const product = await res.json();
 
  return NextResponse.json({ product });
}
``` 

## 2.3 Data Fetching 方式調整
### 2.3.1 新的寫法並不透過 getStaticProps、getServerSideProp 去要資料
```
async func getData() {
  const res = await fetch ("https://api.xxx.com/...");
  return res.json();
}

export default async function About() {
  const name = await getData();
  return "...";
}

```
### 2.3.2  新增 use hook 可以將非同步的結果回傳回來
```
use(getData(id))
```
### 2.3.3 server side 改寫了元生的 fetch api ，並預設有cache 機制，且官方並不建議包裝fetch 在client component 
### 2.3.4 revalidate  
SSG：頁面預設就是 SSG  
SSR：在元件宣告為非同步，且請求時必須關閉緩存，並在請求參數中的cache欄位設置為 no-store、no-cache 或者設置revalidate 為 0 的時候，才會是動態服務端渲染。  
CSR：在使用 "use client" 的客戶端元件中，在Use Effect 後請用的渲染的元件  
ISR：在 fetch 請求中設置 revalidate，或者在 page.tsx 宣告  revalidate。
```
app/page.tsx
export const revalidate = 60; // revalidate this page every 60 seconds
```
P.S. 過去的 pages/api/revalidate 的web hook 仍然有效，但要在page fodler

## 3. 提供 [meta api](https://nextjs.org/docs/app/building-your-application/optimizing/metadata#static-metadata) 替代  next/head，更容易的針對每個頁面給不同 seo 的 meta data  
### 3.1 Static Metadata
```
import { Metadata } from 'next';
 
export const metadata: Metadata = {
  title: '...',
  description: '...',
};
 
export default function Page() {}
```
### 3.2 Dynamic Metadata
```
import { Metadata, ResolvingMetadata } from 'next';
 
type Props = {
  params: { id: string };
  searchParams: { [key: string]: string | string[] | undefined };
};
 
export async function generateMetadata(
  { params, searchParams }: Props,
  parent?: ResolvingMetadata,
): Promise<Metadata> {
  // read route params
  const id = params.id;
 
  // fetch data
  const product = await fetch(`https://.../${id}`).then((res) => res.json());
 
  // optionally access and extend (rather than replace) parent metadata
  const previousImages = (await parent).openGraph?.images || [];
 
  return {
    title: product.title,
    openGraph: {
      images: ['/some-specific-page-image.jpg', ...previousImages],
    },
  };
}
 
export default function Page({ params, searchParams }: Props) {}
```

## 4 昇級後受到影響的套件
### 4.1 i18n 套件 ( 推薦 )
剛昇級完後就會發現相關的 i18n 套件無法使用，新版 useRouter 也不提供 locale 可以使用，試了好幾個 i18n 套件，發現這個套件最好用

[相關文章](https://next-intl-docs.vercel.app/docs/next-13/server-components )

```
import { useLocale } from 'next-intl';

const locale = useLocale();
```
## 4.2 react query 注入方式
[相關文章](https://codevoweb.com/setup-react-query-in-nextjs-13-app-directory/)

## 4.4 context api 載入方式
[相關文章](https://codevoweb.com/setup-react-context-api-in-nextjs-13-app-directory/)

## 5 [Turbopack](https://nextjs.org/docs/architecture/turbopack)( 仍在 Beta )
最後可以持續觀注的，Next.js 13 加了一個名為 Turbopack 的新的 JavaScript 打包工具，它被稱為 Webpack 的繼承者，Turbopack 由 Webpack 由 Rust 撰寫，號稱比原始 Webpack 快 700 倍（並且比 Vite 快 10 倍）。

## 6. 結論
無可否認，Next js 的更新速度令人驚訝，經常在我醒來之後就有了新的穩定版本，每次改版都會有點小陣痛，但大概都花個一至兩天就能昇級，也保留舊的寫法。  

app route 改動的幅度有點大，且有點痛，但 app route出現，正式掀開 server side component 的序幕。

## 附錄 - 一些快速昇級的 powershell
###  1.寫了一個 powershell  快速將 page folder 搬到 app folder 
```
# Get a reference to all tsx files in the src\pages directory.
$files = Get-ChildItem -Path "src\pages" -Filter "*.tsx"

# For each file, create a new directory in src\app with the same name as the file (without extension),
# move the file to the new directory, rename it to page.tsx, and prepend 'use client;' to it.
foreach ($file in $files) {
    # Create new directory.
    $newDir = New-Item -Path "src\app\$($file.BaseName)\" -ItemType Directory

    # Move and rename the file.
    $newFile = Move-Item -Path $file.FullName -Destination "$($newDir.FullName)\page.tsx" -PassThru

    # Add 'use client;' to the beginning of the file.
    $content = Get-Content -Path $newFile.FullName
    $newContent = 'use client;' + "`n" + $content
    Set-Content -Path $newFile.FullName -Value $newContent
}

pause
```

### 2.用 powershell 快速將元件轉成 client side 元件的  
```
# Get a reference to all tsx files in the src\pages directory.
$files = Get-ChildItem -Path "src\pages" -Filter "*.tsx"

# For each file, create a new directory in src\app with the same name as the file (without extension),
# move the file to the new directory, rename it to page.tsx, and prepend 'use client;' to it.
foreach ($file in $files) {
    # Create new directory.
    $newDir = New-Item -Path "src\app\$($file.BaseName)\" -ItemType Directory

    # Move and rename the file.
    $newFile = Move-Item -Path $file.FullName -Destination "$($newDir.FullName)\page.tsx" -PassThru

    # Add 'use client;' to the beginning of the file.
    $content = Get-Content -Path $newFile.FullName
    $newContent = 'use client;' + "`n" + $content
    Set-Content -Path $newFile.FullName -Value $newContent
}

pause
```

### 3. 用Powershell 遍歷資料夾下的Json 合併成在一個新的 JSON 檔案
```
# 初始化空的 Hashtable
$combinedJson = @{}

# 指定資料夾路徑
$folderPath = 'C:\path\to\json\files'

# 尋找所有 .json 檔案
Get-ChildItem -Path $folderPath -Filter *.json | ForEach-Object {
    # 獲取檔案名稱並移除 .json 副檔名
    $propertyName = $_.BaseName

    # 讀取 JSON 檔案內容
    $content = Get-Content $_.FullName | ConvertFrom-Json

    # 將 JSON 內容加入到 combinedJson 中，使用檔案名稱作為屬性
    $combinedJson[$propertyName] = $content
}

# 將合併的 JSON 轉換為字符串並寫入到一個新的 JSON 檔案
$combinedJson | ConvertTo-Json | Set-Content -Path "$folderPath\combined.json"

```

---

## 關於本文與作者

本文出自 [Mark Ku's Blog](https://blog.markkulab.net/post/nextjs-upgrade-app-route)

授權條款： [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — 轉載或引用請註明作者並附上原文連結

### 關於作者

**[Mark Ku](https://blog.markkulab.net/author/mark-ku)** — Software Solution Provider

- 10+ 年資深軟體工程師，現為 AI 應用 Builder
- 專注大型平台架構設計，從北美電商到AI SaaS訂閱收費系統
- 結合 AI Agent 與自動化，打造高效可演進的產品技術基礎

### 作者開發的免費工具

以下工具皆可免費使用：

- [免費 PDF 簽名工具](https://blog.markkulab.net/tools/pdf-sign): 線上 PDF 簽名工具，瀏覽器內完成手繪、打字、上傳簽名，可拖曳放置、縮放、下載。所有處理都在你的裝置完成，檔案不會上傳。
- [VS Code Refactory](https://blog.markkulab.net/tools/refactory): Refactory 是一款 VS Code 重構擴充套件：34 個重構動作、37 條 code smell 檢查、Code Health 儀表板、18 種語言、534 支測試。懂你的專案慣例：介面放哪、DI 註冊寫在哪、'use client' 該不該加；還會用 git 修改頻率 × 複雜度排出「該先修哪個檔案」，並一鍵把壞味道交給你自己電腦上的 Claude Code 修。免費使用，原始碼不離開你的機器。
- [DB-Kit 資料庫管理工具](https://blog.markkulab.net/tools/db-kit): DB-Kit 是一個用 Tauri + Rust + React 打造的輕量跨平台資料庫管理工具，用單一一致的介面同時管理 MySQL、MariaDB、PostgreSQL、SQL Server、Oracle、SQLite、MongoDB、Redis、Kafka、Elasticsearch 與 RabbitMQ 十一種資料來源：連線密碼以 OS keychain 加密、SSH Tunnel、完整 CRUD、視覺化查詢建構器、多結果集同時顯示、跨連線資料傳輸與比對同步、Excel / CSV 匯入匯出、執行計畫視覺化、ER 圖、排程備份、SQL 壓力測試（p50～p99 延遲百分位）、15 條規則的 SQL 審查、Kafka 訊息瀏覽與監控告警；繁中 / 英文雙語介面，內建 AI 助手（自然語言生成 SQL、AI 審查與調校建議）與命令列工具 dbk。免費開源（MIT），提供 Windows / macOS / Linux 安裝檔。
- [VS Code Super Mermaid](https://blog.markkulab.net/tools/super-mermaid): Super Mermaid 是一款 VS Code 擴充套件：開箱即用的漂亮 Mermaid 圖表，自動上色、即時預覽、滑鼠平移縮放、PNG / SVG 高解析匯出，內建 21 種範本與多種主題。免費開源（MIT）。
- [React Super Mermaid](https://blog.markkulab.net/tools/react-super-mermaid): react-super-mermaid 是一個開源 React 元件庫：一行 <MermaidViewer> 即可渲染漂亮的 Mermaid 圖表，內建 colorful / sketch 主題、平移縮放、圖內搜尋、SVG / PNG 高解析匯出。輕量、SSR 安全、完整 TypeScript 型別。免費開源（MIT）。
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/tools/jira-super-mermaid): Atlassian Forge app：在 Jira issue 與 Confluence 內文直接寫 Mermaid 語法，畫流程圖、時序圖、狀態機與甘特圖。11 種圖表、SVG / PNG 匯出、明暗主題、完整中日韓文字支援。取得 Runs on Atlassian 資格：圖表存在你自己的站台，app 不呼叫任何第三方服務。免費，即將上架 Atlassian Marketplace。
- [Mermaid 線上預覽](https://blog.markkulab.net/tools/mermaid-preview): 在瀏覽器裡寫 Mermaid、即時看圖，整張圖表壓進網址就能分享。免註冊、不上傳伺服器，相容 mermaid.live 的分享連結。
- [React Intl Phone Number](https://blog.markkulab.net/tools/react-intl-phone-number): react-intl-phone-number 是一個開源 React 元件：framework-agnostic、不依賴 antd，提供 E.164 進出、可搜尋國旗 / 國碼下拉、可配置驗證等級（strict / mobile-strict / loose）、可主題化 CSS 與 i18n，電話邏輯由 google-libphonenumber 驅動。輕量、完整 TypeScript 型別。免費開源（MIT）。
- [Uptime Kuma Cluster](https://blog.markkulab.net/tools/uptime-kuma-cluster): 把單機版 Uptime Kuma 改造成高可用叢集：OpenResty + Lua 智慧負載平衡、MariaDB 共享狀態、健康檢查與自動 Failover，附叢集管理 REST API，一行 Docker Compose 啟動。免費開源（MIT）。
- [特教專案](https://blog.markkulab.net/education): 為特殊教育學生製作的學習教材

### 每日 Podcast

- [科技新鮮事](https://blog.markkulab.net/category/tech-news): 每日精選 AI 與科技趨勢，透過語音摘要快速掌握最新技術動態，涵蓋 AI 應用、軟體架構、DevOps 與工程實戰。 — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/category/ai-stock-chat): 每個交易日用 AI 分析台股盤勢，以雙人對話聊當天的盤中觀察與隔日預測。 — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml

### 電子報

[訂閱電子報](https://blog.markkulab.net/subscribe) — 第一時間收到新文章通知，無垃圾信、隨時可取消訂閱。
