niskan516
~/blog ~/projects ~/about
← ~/blog

2026-02-20

從 Next.js 遷移到 Astro:一次值得的重寫

為什麼我把個人網站從 Next.js 完全重寫成 Astro,以及這個決定帶來了什麼。

我的個人網站用 Next.js 寫了將近兩年。它能用,但每次打開專案都有一種奇怪的不適感——一個靜態展示網站,卻帶著 React runtime、hydration、_app.tsx_document.tsx,還有一堆我根本用不到的機制。

最後我決定重寫。用 Astro。以下是這個過程。


為什麼要換

Next.js 是一個優秀的框架。對於需要動態資料、身份驗證、複雜路由的應用來說,它依然是我的首選。但個人網站不是應用。

舊網站的問題很具體:

JavaScript bundle 太重。 一個沒有任何互動的頁面,卻要下載完整的 React runtime。使用者打開頁面,瀏覽器執行了大量 JavaScript,然後什麼都沒有發生——因為頁面根本沒有需要 JavaScript 的地方。

pages/ 目錄越來越亂。 _app.tsx_document.tsxgetStaticPropsgetStaticPaths——每個頁面都要思考這些,即使只是一個純靜態的關於頁。

維護感覺像在維護一個產品。 依賴項繁多,eslint、prettier、各種 Chakra UI 的配置。每次 npm install 都是一次小小的冒險。


為什麼選 Astro

Astro 的核心主張很簡單:預設零 JavaScript。只有你明確需要互動的部分才會送出 JavaScript,其餘全部是靜態 HTML。

對個人網站來說,這個哲學完全對齊。

另外幾個吸引我的點:

  • Content Collections:內建的 Blog 文章管理,有型別安全的 frontmatter schema,不需要自己處理 Markdown
  • Islands Architecture:需要互動的地方用 SolidJS 或 React,其他地方不帶任何框架
  • .astro 語法:component-scoped CSS、直接在 frontmatter 寫 server logic,感覺很乾淨
  • Cloudflare 適配器:一行指令部署到 Cloudflare Workers,不需要思考 Node.js server

遷移過程

內容結構

舊版的頁面內容是散落在各個 .tsx 檔案裡的 JSX 字串。沒有 CMS,沒有 Markdown,就是硬寫在 component 裡。

新版用 Astro 的 Content Collections:

src/content/blog/posts/
├── nextjs-to-astro.mdx
├── vibe-coding.mdx
└── rss-still-matters.mdx

每篇文章有 frontmatter,schema 在 content.config.ts 定義。加一篇文章就是加一個 .mdx 檔案,完全不需要動程式碼。

樣式

舊版用 Chakra UI 加自訂的 SCSS。遷移後全部換成 Tailwind CSS v4 加 CSS 自訂變數。

設計 token 統一定義在 :root

:root {
--color-base: #0f0f0f;
--color-cyan: #22d3ee;
--font-mono: "JetBrains Mono", monospace;
}

不需要任何 JavaScript,不需要 theme provider,不需要 useColorMode。主題切換就是在 <html> 上加 .light class,CSS 變數自動覆蓋。

路由

Next.js 的 pages/ 路由對應到 Astro 的 src/pages/ 幾乎是一比一。差別在於 Astro 的路由檔案是 .astro,而不是 .tsx

動態路由的語法也差不多:

Next.js: pages/blog/[slug].tsx
Astro: src/pages/blog/[...slug].astro

[...slug] 而不是 [slug] 是因為 Content Collections 的文章 ID 包含目錄路徑(posts/hello-world),需要 catch-all route。

部署

舊版部署在 Vercel,完全自動,沒什麼好說的。

新版的目標是 Cloudflare Pages。設定 @astrojs/cloudflare 適配器,加上 GitHub Actions workflow,每次 push 到 main 自動部署。

- name: Build
run: bun run build
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
command: pages deploy dist --project-name=niskan516-space

遷移後的差異

幾個具體的變化:

Next.jsAstro
JavaScript(首頁)~120KB~15KB
依賴項數量4718
冷啟動建置時間~25s~4s
部署平台VercelCloudflare Pages
套件管理器pnpmBun

JavaScript 的差距最明顯。舊版首頁送出的 JavaScript 幾乎全都是框架本身,沒有任何業務邏輯。


值不值得

對個人網站來說,完全值得。

重寫本身花了一個下午(加上 Claude Code 的協助,速度快了很多)。現在的架構比舊版簡單太多——沒有多餘的抽象,每個部分都有明確的理由存在。

如果你有一個主要是靜態內容的網站,但還在用 React 框架,可以認真考慮 Astro。不是所有網站都需要一個 SPA 框架——有時候靜態 HTML 就是正確答案。