
從 Hexo 到 Quartz:為什麼搬家、怎麼搬、學到了什麼
如果你跟我一樣,部落格用 Hexo 跑了好一陣子,文章也累積了兩百多篇,某天突然覺得「這堆文章之間怎麼毫無關係?」——那這篇文章就是寫給你的。
這篇會分享我從 Hexo 搬到 Quartz 的完整過程:為什麼要搬、怎麼選的、搬家踩了哪些坑、搬完以後有什麼改變,以及一些技術細節和給同樣想搬家的人的建議。
一、為什麼要搬家
先說結論:不是 Hexo 不好,而是我的需求變了。
1.1 文章之間缺乏連結
Hexo 的文章本質上是一篇一篇獨立的 blog post。你寫了一篇 JavaScript 閉包,又寫了一篇 React Hooks,這兩篇文章之間除了你自己腦中知道有關聯以外,在網站上完全看不出來。
讀者看完一篇文章,能做的事只有「回到首頁看列表」或「點分類/標籤」。但分類和標籤終究只是標記,不是真正的知識連結。
1.2 知識是列表,不是網
Hexo 的首頁就是一個按時間排序的文章列表。這對新聞型部落格來說很合理,但對技術筆記來說是災難。我越來越覺得,知識應該是「網狀」的——A 引用 B,B 又連到 C,讀者可以順著脈絡探索。
1.3 Theme 維護令人崩潰
Hexo 的 theme 生態看起來很豐富,但實際上:
- 很多 theme 已經停更了
- 想改一個小地方要翻一堆 EJS/Pug 模板
- 升級 Hexo 版本 theme 就爛掉
- 不同 theme 的 config 格式不統一
我花在「讓部落格看起來沒壞掉」的時間,比花在「寫文章」的時間還多,這本末倒置了。
二、為什麼選 Quartz
在決定搬家之前,我認真比較了幾個主流選項:
| 特性 | Quartz | Hugo | Gatsby | Docusaurus | Obsidian Publish |
|---|---|---|---|---|---|
| Wikilinks 支援 | 原生支援 | 需外掛 | 需外掛 | 不支援 | 原生支援 |
| Graph View | 內建 | 無 | 無 | 無 | 內建 |
| Obsidian 格式相容 | 完整 | 部分 | 部分 | 不支援 | 完整 |
| 建置速度 | 快 | 極快 | 慢 | 中等 | N/A(雲端) |
| 自訂彈性 | 高(TypeScript) | 高(Go Template) | 極高(React) | 中等 | 低 |
| 部署成本 | 免費(GitHub Pages) | 免費 | 免費 | 免費 | 付費(/月) |
| 學習曲線 | 中等 | 中等 | 高 | 低 | 極低 |
| 反向連結 | 內建 | 無 | 需外掛 | 無 | 內建 |
Quartz 的殺手功能
最後讓我選 Quartz 的三個關鍵理由:
1. Wikilinks
用 [[文章名稱]] 就能建立文章之間的連結。不用記 URL、不用翻 slug,寫作的時候想到相關文章就直接連過去。這完全改變了寫作的心態——從「寫完一篇是一篇」變成「每篇都是知識網路的一個節點」。
2. Graph View(知識圖譜)
每篇文章右側都有一個互動式的知識圖譜,可以看到這篇文章和哪些其他文章有關聯。讀者可以拖拉、縮放,順著圖譜探索整個知識庫。這不是花俈的裝飾,是真的有用。
3. Obsidian 格式全面相容
我平常就用 Obsidian 寫筆記,Quartz 直接吃 Obsidian 的 Markdown 格式(包括 callout、wikilink、嵌入等)。寫作流程從「Obsidian 寫 → 轉格式 → 發布」變成「Obsidian 寫 → 發布」。
三、搬家過程
搬兩百多篇文章聽起來很恐怖,但其實拆開來看每一步都不難。
搬家流程圖
flowchart TD A[Hexo source/_posts/] --> B[分析 frontmatter 格式] B --> C[AI 批次轉換 frontmatter] C --> D[處理圖片路徑] D --> E[重新設計分類結構] E --> F[加入 wikilinks 交叉引用] F --> G[品質篩選與分級] G --> H{品質 OK?} H -->|是| I[放入 Quartz content/] H -->|否| J[標記為 draft 或刪除] I --> K[設定 quartz.config.ts] K --> L[本地預覽測試] L --> M[部署到 GitHub Pages] style A fill:#d79921,color:#282828 style M fill:#98971a,color:#282828 style J fill:#cc241d,color:#fbf1c7
3.1 Frontmatter 轉換
Hexo 和 Quartz 的 frontmatter 格式有些差異。主要差異:
abbrlink在 Quartz 中不需要(Quartz 用檔案路徑當 URL)index_img要換成 Quartz 的圖片處理方式categories的巢狀陣列要攞平date格式建議統一成YYYY-MM-DD
3.2 圖片路徑大搬遷
這是最惱人的一步。我的做法是把所有圖片集中到 content/static/images/ 下,按分類建子資料夾,用腳本批次替換文章中的圖片路徑。
3.3 分類結構重新設計
搬到 Quartz 以後,因為有了 wikilinks 和資料夾結構的天然支援,我重新設計了分類。每個資料夾就是一個知識領域,資料夾裡可以有 index.md 當作該領域的入口頁面。
3.4 兩百多篇品質參差:怎麼辦?
我分了三個等級:
- A 級(直接搬):內容完整、有參考價值的文章,約 60 篇
- B 級(改了再搬):主題有價值但需要重寫或補充,約 80 篇
- C 級(先不搬):過時、太短、或已被其他文章覆蓋的
先把 A 級搬過去讓網站能用,B 級慢慢改,C 級看心情。
3.5 AI 輔助批次轉換
手動改兩百多篇 frontmatter?別鬧了。我用 AI 寫了腳本來批次處理:Frontmatter 轉換、自動補 description、分類映射、Wikilink 建議。AI 省了我大概 80% 的時間。
四、搬完之後的改變
搬完之後最大的感受是:終於覺得自己的部落格是一個「知識庫」而不只是一堆文章的集散地。
4.1 文章有「關係」了
以前寫完一篇就是一篇,現在寫完一篇會自然地想:這篇跟哪些已有的文章有關聯?該加哪些 wikilinks?
舉個例子,我寫一篇 React useEffect 的文章時,會順手加上 [[javascript/closure|JavaScript 閉包]] 和 [[react/hooks-overview|React Hooks 總覽]] 的連結。讀者看完 useEffect,可以直接跳到閉包的原理,或是回到 Hooks 的全局視角。
4.2 寫作方式改變
在 Hexo 時代,我寫文章的心態是「產出一篇完整的東西」。在 Quartz 之後,變成「在知識網路上新增一個節點」。這個轉變聽起來很小,但實際影響很大:
- 不再害怕寫短文章:一個概念值得一篇獨立的筆記,即使只有 200 字,因為它可以被其他文章引用
- 更願意回頭更新舊文:因為舊文被新文連結引用了,維護它就有了動力
- 知識累積有複利效應:文章越多,彼此之間的連結越密集,整體價值就越高
4.3 跨系列引用變得自然
以前在 Hexo 要做跨系列引用,得手動複製 URL、寫 [連結文字](超長路徑)。現在只要 [[文章名稱]],甚至可以用 [[文章名稱|顯示文字]] 自訂顯示。
這個改變看似微小,卻讓我「願意」去做交叉引用。以前嫌麻煩就不連了,現在隨手就連。
五、Quartz 技術細節
這一節給想深入了解 Quartz 的人。
5.1 quartz.config.ts
Quartz 的核心設定檔是 quartz.config.ts,用 TypeScript 寫的,有型別提示,改起來比 Hexo 的 _config.yml 舒服很多。
幾個重要設定:
const config: QuartzConfig = {
configuration: {
pageTitle: "你的網站名稱",
enableSPA: true, // 單頁應用模式,頁面切換更流暢
enablePopovers: true, // hover 預覽連結內容
locale: "zh-TW", // 繁體中文
baseUrl: "your-username.github.io",
},
plugins: {
transformers: [
Plugin.ObsidianFlavoredMarkdown({
enableInHtmlEmbed: false,
}),
Plugin.CrawlLinks({
markdownLinkResolution: "shortest", // wikilink 解析策略
}),
],
},
}CrawlLinks 的 markdownLinkResolution: "shortest" 是個很重要的設定。它讓你用最短的檔名就能連結到文章,不用寫完整路徑。例如 [[closure]] 就能連到 javascript/closure.md。
5.2 Layout 自定義
Quartz 的 layout 設定在 quartz.layout.ts,可以調整每個頁面區塊要放哪些元件:
export const defaultContentPageLayout: PageLayout = {
beforeBody: [
Component.ArticleTitle(),
Component.ContentMeta(),
Component.TagList(),
],
left: [
Component.PageTitle(),
Component.Search(),
Component.Explorer(), // 檔案瀏覽器
],
right: [
Component.Graph(), // 知識圖譜
Component.TableOfContents(),
Component.Backlinks(), // 反向連結
],
}Graph 元件可以進一步調整節點大小、連結距離、是否顯示標籤等。Backlinks 元件也可以設定是否顯示引用上下文(showContext: true),讓讀者不用點進去就能看到「哪篇文章的哪段話引用了這篇」。
5.3 部署方式
我用 GitHub Actions 自動部署到 GitHub Pages。流程很簡單:
- 推 code 到
mainbranch - GitHub Actions 自動跑
npx quartz build - 產出的靜態檔案部署到 GitHub Pages
Quartz 官方就有提供 GitHub Actions 的範本,幾乎不用改就能用。
5.4 常踩的坑
搬家過程中遇到一些值得注意的問題:
- 中文檔名要小心:雖然 Quartz 支援中文檔名,但建議還是用英文,避免 URL encode 造成的各種問題
- 圖片路徑是相對於 content 根目錄:不是相對於文章所在位置,這跟 Hexo 不一樣
- Mermaid 圖表要注意中文字元:有些特殊標點在 Mermaid 裡會造成渲染錯誤
- frontmatter 的 date 格式:建議統一用
YYYY-MM-DD,不要用YYYY/MM/DD或帶時間的格式 - SPA 模式下的外部連結:開了
enableSPA: true以後,要確認外部連結有加target="_blank"
六、給想搬家的人的建議
如果你也在考慮從 Hexo(或其他 SSG)搬到 Quartz,這是我的幾點建議:
6.1 不用一次搬完
最大的錯誤就是想一次把所有文章都搬過去。你會被海量的格式轉換淊沒,然後放棄。
我的建議是:先搬 10-20 篇你最滿意的文章,把網站先架起來。確認一切正常後,再慢慢搬剩下的。
6.2 先搬結構,再提升品質
先把資料夾結構和分類設計好,把文章放進對應的位置。內容品質可以之後再慢慢提升。結構對了,後面改內容就輕鬆很多。
6.3 善用 AI 輔助
重複性高的工作(frontmatter 轉換、格式修正、補 description)讓 AI 來做。把你的時間花在「重新組織知識架構」和「建立文章之間的連結」這些 AI 做不好的事情上。
6.4 搬家是重新整理知識的好機會
不要把搬家當成苦差事。這其實是一個很棒的機會,讓你重新審視自己寫過的東西:
- 哪些文章已經過時了?
- 哪些主題值得擴充?
- 哪些文章之間其實有關聯,只是以前沒有連起來?
- 你的知識體系有哪些缺口?
搬完以後你會對自己的知識庫有一個全新的認識。
6.5 記得設定 redirect
如果你的舊部落格有被搜尋引擎收錄,搬家後記得做好轉址。可以在 GitHub Pages 上設定 _redirects 檔案,或是用 meta refresh 的方式把舊 URL 導向新 URL。不然你辛苦累積的 SEO 就白費了。
結語
從 Hexo 搬到 Quartz,表面上是換了一個靜態網站產生器,實際上是改變了我對「部落格」這件事的理解。
部落格不只是「按時間排列的文章列表」。它可以是一個活的知識網路,文章之間互相引用、互相補充,讀者可以順著自己的興趣和脈絡探索。
搬家的過程確實花了不少時間,但搬完以後回頭看,這是一個非常值得的投資。如果你的部落格也累積了一定數量的文章,而且你希望這些文章能產生「1+1>2」的效果,那 Quartz 值得你認真考慮。