TECH NOTES

自己架 Blog:我的 Astro + Cloudflare Pages 實作紀錄

封面圖

我在 Medium 寫部落格已經好一段時間了,不過 Medium 的編輯與發布體驗對我來說有點微妙,介於方便跟不方便之間。尤其我在本機撰寫的草稿都是 Markdown 格式,但要發布到 Medium 時,還是需要 case by case 額外處理。

所以,這次我想做一個小實驗:保留原本的 Medium,同時建立一個由自己管理的 Blog。

我的目標很單純,所以這個自己架的 Blog 暫時不打算做會員、留言、瀏覽次數或後台,也不需要 database。文章繼續使用 Markdown,網站最後能輸出成純靜態檔案就好。 和 AI 討論後,它建議我用 Astro 搭配 Cloudflare Pages 發布就好。


Cloudflare Page

這次 Blog 使用的技術組合大致如下:

  • Astro 負責頁面、文章與 static build
  • Markdown 儲存文章內容
  • Content Collections 檢查 frontmatter
  • Astro Image 處理 responsive images
  • GitHub 保存原始碼與文章
  • Cloudflare Pages 自動 build 與發布

完成首頁、文章頁、About、tags、分頁與 SEO metadata 後,真正花時間的反而是版面調整。

技術文章需要清楚的標題層級、code block 與適當的行距;旅遊文章則需要較寬的照片,但手機截圖不能被強行放大。繁體中文與英文混排時,字級、段落距離和換行也會直接影響閱讀感受。

這些調整沒有什麼神奇的解法,主要就是找幾篇不同類型的文章反覆比較:有大量照片的旅遊文章、有 YAML 與 command line 的技術文章,以及包含窄圖與手機截圖的舊文章。

除了調整版面,真正麻煩的是匯入既有的部落格文章內容。

我手上有六百多篇文章,而且不少文章曾經從痞客邦搬到 Medium。Markdown 草稿還在,但搬到 Medium 後上傳的圖片只存在 Medium 的文章與 CDN 裡。如果要讓新的 Blog 真正獨立,圖片也必須一起取回來,不能繼續依賴外部網址。

因此我做了一個一次性的匯入流程:讀取 Medium export,轉成 Markdown,下載文章圖片,再把 Markdown 與圖片放進同一個文章資料夾。這樣未來搬動文章時,一個 folder 就包含了它需要的內容。

src/content/posts/article-slug/
├── index.md
├── cover.jpg
├── image-02.jpg
└── image-03.jpg

大量下載圖片時也遇到 429 Too Many Requests。最後只能把流程改成可以中斷後繼續、限制圖片下載速度,並在被限流時逐步延長等待時間。這比追求一次全部跑完可靠得多。

匯入成功不代表文章適合直接發布。舊平台的 HTML 轉成 Markdown 後,可能會出現重複摘要、清單黏在一起、code block 遺失,或圖片尺寸不合理等問題。

所以所有歷史文章預設都是 draft: true。我另外做了一個簡單的審核 queue,依原始發布日期列出文章;看過內容、圖片、description、tags 與網址後,才明確指定要發布哪些文章。

老實說這個步驟有點煩瑣,但我寧願逐批處理,也不想讓六百多篇未確認的內容同時出現在新網站。


Astro 可以在 build 時替本機圖片產生 responsive image,這對照片很多的文章很方便。不過每一張原圖如果產生多個尺寸,最後的部署檔案數量會快速增加。

Cloudflare Pages 的免費方案對單一網站有檔案數量目前設有 20,000 個檔案的上限,每月則提供 500 次 build。由於 Astro 會替每張圖片產生不同尺寸的最佳化版本,因此文章圖片數量會直接影響最後的部署檔案數量。

參考:Cloudflare Pages Platform Limits.

完整建立所有圖片時,這個 Blog 一度很接近限制,因此最後只保留手機版與原始寬度兩個候選尺寸。對目前的版面來說已經夠用,也讓完整 archive 能繼續維持在免費額度內。


網站完成後,我把 repository 連接到 Cloudflare Pages。main 是正式環境,其他 branch 與 Pull Request 則會建立 Preview deployment。

現在的流程是:

  1. 在文章自己的資料夾編輯 index.md 並加入圖片。
  2. 保持 draft: true 在本機預覽與修改。
  3. 確認內容後改成 draft: false。
  4. commit、push 並建立 Pull Request。
  5. 使用 Cloudflare Preview 檢查實際頁面與社群分享資訊。
  6. merge 進 main 後自動發布。

首頁與每篇文章都有自己的 title、description、canonical URL、Open Graph metadata 與分享圖片。

Facebook 分享偵錯工具


能自己掌控這些東西,感覺真的還不錯。尤其是 Open Graph 圖片的 metadata,Medium 平台好像壞掉(或是拔掉這個功能?)有一陣子了,造成分享到 social network 的文章都沒有圖片,很是困擾。

目前這個 Blog 已經可以正常發布文章,但 Medium 的內容仍然會保留,新文章也會同步發布。

接下來除了繼續寫新文章,也會逐批檢查過去的草稿。等內容與流程都穩定後,再決定是否購買自己的 domain,以及這個自建版本和 Medium 平台之間要如何分工。

至少現在,每篇文章的 Markdown、圖片與網址,都有一個清楚而且可以長期維護的地方。

最後的最後,我目前這個自建平台網址是 https://ddsakura.pages.dev/ ,歡迎大家有空來逛逛!