前言
這個部落格已經陪伴我將近五年,歷經了兩次重大改版。第一版是用 Gatsby + MDX 自建的靜態部落格;這一次,是第二次改版目標更高,用現代化的 Next.js 15 重建,並整合完整的 AI 生成管線。
今年初,我決定動手了。而且我給自己一個挑戰目標:用 Claude Code AI 協作,一天之內完成全新部落格的核心架構。
結果?真的辦到了。這篇就是這次完整的改版紀錄,從舊網站的痛點、新架構的設計決策、AI 協作開發的實際體驗,到最後整合 Vertex AI Veo 3.1 生成展示影片的完整流程。
一、舊網站技術架構:痛在哪裡?
第一版部落格用的是 Gatsby + gatsby-theme-flexiblog,文章以 MDX 格式撰寫,直接存在 Git 倉庫裡,透過 Gatsby 在 build time 靜態生成頁面。當時算蠻現代的,但跑了幾年後,問題越來越多。
首先是主題客製化受限。gatsby-theme-flexiblog 基於主題系統(Theme Shadowing)做客製化,雖然可以覆寫元件,但設計風格基本上是定死的。想大幅調整排版或加新的互動元素,每次都在跟主題底層搏鬥,改一個小東西可能要翻好幾層 source code。
再來是 Gatsby 生態系的維護負擔。說實話,Gatsby 在 React 生態系的地位已經被 Next.js 取代了。plugin 版本衝突、GraphQL 資料層搞得很複雜、偶發的 build 失敗,維護成本越來越高,每次升級都提心吊膽。
最後是 MDX 支援度不夠好。自訂元件的整合很繁瑣,程式碼區塊的語法高亮要靠 plugin 配一堆東西。想在文章裡嵌個互動式元件或影片播放器?那個設定量會讓你想放棄。
二、新網站技術架構:解決了什麼?
新網站選了以下這套技術組合,截至目前已經累積 244 篇文章:
| 層面 | 技術選擇 |
|---|---|
| 框架 | Next.js 15 + React 19 |
| 語言 | TypeScript |
| 樣式 | Tailwind CSS 4 |
| 打包工具 | Turbopack(預設) |
| 內容格式 | MDX(gray-matter 解析) |
| 部署 | Vercel |
| 留言 | Giscus(GitHub Discussions) |
| 分析 | Google Analytics 4 |
MDX 為核心的內容架構
每篇文章都是一個獨立目錄,結構很單純:
public/content/posts/{handle}/
├── index.mdx # 文章本文 + frontmatter
├── summary.json # AI 生成的摘要文字
├── audio/
│ └── summary.mp3 # TTS 語音摘要
├── images/
│ └── cover.webp # AI 生成封面圖
└── videos/
└── demo.mp4 # AI 生成展示影片
Frontmatter 定義了文章所有的 metadata標題、日期、分類、標籤、縮圖路徑,還有影片 URL、音訊 URL 等多媒體欄位。
SEO 301 Redirect 無縫遷移
改版最怕的就是舊網址全部 404,多年累積的 SEO 排名一夕歸零。所以我設計了一套 301 redirect 機制:
舊 URL: /my-post-slug
↓ middleware.ts 攔截(Edge Runtime)
↓ 查詢 redirect-map.json
新 URL: /post/my-post-slug (HTTP 301)
每篇文章的 frontmatter 都有 oldSlug 欄位記錄舊路徑。build 前 generate-redirect-map.mjs 會自動掃描所有文章,生成對照表 redirect-map.json:
{
"/my-old-slug": "/post/my-new-handle"
}
middleware.ts 在 Edge Runtime 攔截請求、查表、回 301,還額外做了大小寫不敏感比對(舊平台有些 URL 大小寫混用)。246 篇遷移文章的舊連結全部無縫轉址,搜尋引擎累積的權重完整保留。
App Router + 靜態生成
Next.js 15 的 App Router 讓路由組織更直覺,generateStaticParams 在 build time 預生成所有文章頁面,首屏載入速度遠超舊平台。
Turbopack 開發體驗
舊的 Webpack 在大型專案下啟動 dev server 要等好幾秒。換成 Turbopack 之後,Fast Refresh 快了近 10 倍,改個元件幾乎即時看到結果,開發體驗好太多了。
三、AI 自動化內容生成管線
新部落格最大的差異化,就是這套 AI 媒體生成管線。所有腳本都在本地離線跑(省 API 費用、不怕 Vercel timeout),生成的東西直接當靜態資源提交到 Git。
封面圖生成(Gemini Image)
npm run generate-post-cover -- --handle migrate-blog-with-ai
腳本讀取文章標題跟分類,讓 gemini-2.5-flash 生成圖片提示詞,再由 gemini-3.1-flash-image-preview 生成 16:9 技術風格封面圖。每個分類有對應的色系AI 用紫色、Frontend 用藍色、DevOps 用綠色,視覺上蠻統一的。
AI 語音摘要(Gemini + VoAI 離線 TTS)
npm run generate-audio -- --handle migrate-blog-with-ai
腳本用 Gemini 為每篇文章生成 350-500 字的繁體中文摘要和Podcast,再透過**絕好聲創(VoAI)**離線合成 mp3 音檔。
絕好聲創是一款台灣本土開發的 AI 語音合成工具,支援繁體中文,提供多種自然聲線,帶來自然流暢的中文 AI 配音體驗。
背景音樂(Google Lyria)
npm run generate-music
用 Google 的 Lyria 音樂生成模型,為部落格生成適合閱讀情境的背景音樂。音樂風格由 AI 音樂策展人 persona「Melody」來設計描述。
分類圖示與橫幅
22 個文章分類各有一張 iOS 風格的圖示和橫幅,全部由 Gemini 圖像模型生成,風格蠻一致的。
四、Vertex AI Veo 3.1:用 AI 生成技術展示影片
這是這篇文章的重點技術:用 Google Vertex AI 的 veo-3.1-generate-001 模型,從文字 prompt 直接生成影片。
為什麼要做這件事?
技術文章配上影片確實能幫助讀者理解,但說實話,錄製加剪輯的成本很高,光是設定錄屏軟體就要花不少時間。Veo 3.1 讓我可以用一段文字描述,就產出一段還不錯的技術架構展示影片不用螢幕錄製,不用剪輯軟體。
Veo 3.1 API 呼叫方式
Veo 3.1 用的是 Vertex AI 的 Long-running Operation 模式,因為影片生成需要比較長的時間:
// 1. 發起生成請求
const response = await fetch(
`https://us-central1-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/us-central1/publishers/google/models/veo-3.1-generate-001:predictLongRunning`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
instances: [{
prompt: "A cinematic visualization of a modern Next.js 15 blog architecture: data flowing from MDX files through gray-matter parsing, through React Server Components, rendered as a beautiful dark-themed blog. Indigo and teal color scheme, technical diagram style with glowing nodes and connecting lines."
}],
parameters: {
aspectRatio: "16:9",
sampleCount: 1,
durationSeconds: 8,
generateAudio: false,
}
})
}
)
// 2. 取得 operation name
const { name: operationName } = await response.json()
// 3. 輪詢等待完成
let result
while (true) {
const pollResponse = await fetch(
`https://us-central1-aiplatform.googleapis.com/v1/${operationName}`,
{ headers: { 'Authorization': `Bearer ${accessToken}` } }
)
result = await pollResponse.json()
if (result.done) break
await sleep(10000) // 每 10 秒輪詢一次
}
// 4. 取出影片 base64 並存檔
const videoBase64 = result.response.videos[0].bytesBase64Encoded
fs.writeFileSync(outputPath, Buffer.from(videoBase64, 'base64'))
generate-video.mjs 腳本
scripts/generate-video.mjs 整合了完整的生成流程:
# 為指定文章生成展示影片(從文章標題與描述自動生成 prompt)
npm run generate-video -- --handle migrate-blog-with-ai
# 指定自訂 prompt
npm run generate-video -- --handle migrate-blog-with-ai --prompt "Modern blog architecture visualization"
# 強制重新生成
npm run generate-video -- --handle migrate-blog-with-ai --force
腳本做的事情很單純:讀文章的 title 和 description,用 Gemini 把中文標題轉成適合 Veo 的英文視覺 prompt,呼叫 API 輪詢等待,最後把 .mp4 存到 public/content/posts/{handle}/videos/architecture-demo.mp4。
影片太大?自動上傳 YouTube
Veo 3.1 生成的影片動輒 10-20MB,直接放 Git 倉庫的話 repo 會迅速膨脹。所以 generate-video-youtube.mjs 內建了檔案大小偵測超過 5MB 就自動上傳 YouTube 並刪除本地檔案。
# 自動判斷:影片 > 5MB 就上傳 YouTube,並刪除本地檔案
npm run generate-video-youtube -- --handle migrate-blog-with-ai
# 批次處理最近 5 篇文章
npm run generate-video-youtube:recent -- 5
# 強制重新生成並上傳(即使已有 YouTube URL)
npm run generate-video-youtube -- --handle migrate-blog-with-ai --force
流程大概是這樣:先呼叫 generate-video.mjs 生成影片,檢測檔案大小,超過 5MB 就透過 YouTube Data API v3 上傳,然後自動更新 frontmatter 的 videoUrl 為 YouTube URL,最後刪掉本地影片檔。這樣影片交給 YouTube CDN 託管,Git 倉庫只留 YouTube URL,不會因為 AI 生成影片把 repo 搞爆。
影片嵌入文章
在 frontmatter 加上 videoUrl 就好:
scrollAutoPlay: false
部落格的影片元件會自動處理路徑解析,本地 .mp4 和 YouTube URL 兩種格式都支援。
五、成果對比與未來規劃
流量從一年一萬成長到六萬,增長了 6 倍。這不只是改版本身的效果,更反映了 SEO 結構改善、載入速度提升之後,搜尋引擎給予更高排名的直接結果。
最大的收穫
老實說,最大的收穫不只是一個更好看的部落格,而是一套可重複使用的 AI 內容生成基礎設施。每篇新文章的封面圖、語音摘要、展示影片都能一鍵生成,寫文章的門檻降低了很多以前光是做封面圖就要花半小時,現在一行指令搞定。
接下來想做的事
- 把 Veo 3.1 用在更多場景,像教學流程動畫、架構圖動態展示
- 試試 Gemini 的多模態能力,例如截圖丟進去自動生成說明文字
- 做一個 RAG 知識庫,讓讀者可以直接問部落格文章相關的問題
用一天打造這個新部落格,不是終點,而是一個新起點。
AI 工具讓我把過去需要一週的工作壓縮到一天,而省下來的時間,可以用來想更有價值的問題:下一篇要寫什麼?





























留言