架站筆記

封面圖轉 WebP 省 91%:順便算清楚 Cloudflare Pages 的免費額度

2026-08-09 #Cloudflare Pages#WebP#圖片優化#sharp#效能

幫幾篇文章配上封面圖之後,我冒出一個念頭:這樣一直加圖,Cloudflare Pages 的免費額度會不會爆掉?

實際算完發現:容量完全不是問題,差得非常遠。但真正該擔心的是另一件事——而那件事跟額度無關。這篇記錄完整的量測、Cloudflare Pages 的真實限制,以及最後把 4.1 MB 壓成 375 KB 的做法。

一、先量,再擔心

擔心之前先看數字。三個指令:

1
2
3
du -sh public/                                  # 網站總大小
find public -type f | wc -l # 檔案數
find public -type f -exec du -h {} + | sort -rh | head -8 # 最大的檔案

結果:

1
2
3
4
5
6
7
8
9
7.2M    public/
96 個檔案

1.2M public/images/covers/vectordb-vs-mongodb.png
1.2M public/images/covers/retrieval-permission.png
1000K public/images/covers/rag-fundamentals.png
884K public/images/covers/hybrid-retrieval.png
200K public/css/style.css
148K public/atom.xml

四張封面圖佔了 4.1 MB,是整個網站的 57%

二、Cloudflare Pages 的真實限制

查官方文件,免費方案的限制其實只有三條:

項目 免費方案上限 我的用量 用掉
每次部署的檔案數 20,000 個 96 個 0.5%
單一檔案大小 25 MiB 最大 1.2 MB 5%
每月建置次數 500 次 當天約 20 次 4%
網站總大小 官方沒有設限 7.2 MB
頻寬 / 請求數 靜態資源不計費

以檔案數推算:就算之後每篇文章都配一張圖,還可以再放大約一萬篇。以單檔限制推算:一張圖要 25 MiB 才會被擋,那已經是未壓縮的 4K 攝影原始檔等級。

結論:容量完全不用擔心。 那個「靜態資源不計流量」也值得注意——這是 Cloudflare Pages 相對於多數靜態託管服務的關鍵優勢,文章爆紅不會收到帳單。

順帶一提,之前為在線人數寫的 Cloudflare Worker 也有免費額度(每日 10 萬次請求),同樣算完是綽綽有餘。

三、真正的問題:讀者的載入時間

額度沒事,但量測過程讓我看到另一個數字:首頁一次列出所有文章卡片,等於一進站就要下載 4 MB 的圖片。

這跟 Cloudflare 的帳單無關,是純粹的使用者體驗問題:

  • 手機用 4G,4 MB 大約要等 3~8 秒
  • 卡片圖是首屏內容,讀者第一眼就在等它
  • 這些圖同時是 Open Graph 預覽圖,分享到通訊軟體時也要重新下載

「額度沒爆」和「網站很慢」是兩件事,前者讓我差點忽略後者。量測的價值往往不是驗證你原本的假設,而是讓你看到沒在找的東西。

四、WebP:這類圖的壓縮率高得誇張

我的封面圖全是資訊圖表——大色塊、線條、文字,沒有攝影那種連續色調。這正是 WebP 最擅長的類型。

sharp 轉換(Node.js 的影像處理套件,底層是 libvips):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const sharp = require('sharp');
const fs = require('fs');

const dir = 'source/images/covers';
(async () => {
for (const f of fs.readdirSync(dir).filter(n => n.endsWith('.png'))) {
const src = `${dir}/${f}`;
const out = src.replace(/\.png$/, '.webp');
await sharp(src).webp({ quality: 82 }).toFile(out);

const a = fs.statSync(src).size, b = fs.statSync(out).size;
console.log(`${f}: ${(a/1024).toFixed(0)}KB -> ${(b/1024).toFixed(0)}KB`);
}
})();

安裝時建議加 --no-save

1
npm install --no-save sharp

這樣 sharp 會裝進 node_modules 供這次使用,但不會寫進 package.json。轉圖是一次性的本機工作,Cloudflare 建置時完全不需要它——沒理由讓每次雲端建置都多裝一個 30 MB 的原生套件。

結果

圖片 PNG WebP 縮減
rag-fundamentals 998 KB 69 KB 93%
hexo-giscus 551 KB 64 KB 88%
hexo-site-stats 862 KB 71 KB 92%
hybrid-retrieval 883 KB 96 KB 89%
retrieval-permission 1158 KB 101 KB 91%
vectordb-vs-mongodb 1132 KB 105 KB 91%
合計 5.4 MB 506 KB 91%

整個網站從 7.2 MB 降到 3.7 MB。首頁的圖片流量從 4 MB 掉到不到 400 KB,肉眼看不出畫質差異

quality: 82 是我試過幾個值之後的選擇:90 以上檔案明顯變大但看不出更好,70 以下文字邊緣開始出現模糊。資訊圖有大量文字,這個特性讓它比照片更不能壓過頭。

五、原始檔要留,但不要部署

轉完之後有個容易忽略的細節:PNG 原始檔要留著(日後可能要重新處理、換壓縮參數、或做其他尺寸),但不該被部署出去——不然等於白轉,兩份都上傳。

Hexo 會把 source/ 底下的所有東西原樣複製到 public/。所以做法是把原始檔移出 source/

1
2
mkdir -p assets/covers-original
mv source/images/covers/*.png assets/covers-original/

assets/ 在專案根目錄、不在 source/ 裡,於是它進版控但不進部署——母檔安全地躺在 git 裡,網站上只有 WebP。

然後更新文章的 front-matter:

1
cover: /images/covers/rag-fundamentals.webp    # 從 .png 改成 .webp

驗證一下沒有漏網之魚:

1
2
3
npx hexo clean && npx hexo generate
grep -c 'covers/.*\.png' public/index.html # 應該是 0
grep -c 'covers/.*\.webp' public/index.html # 應該等於有封面的文章數

六、瀏覽器相容性:可以直接用了

早年用 WebP 要準備 <picture> 加 PNG 備援,現在不用了——所有現代瀏覽器都支援 WebP(Safari 從 14 開始,也就是 2020 年 iOS 14 起)。除非你的讀者裡有大量古董裝置,直接單一格式即可。

如果想再進一步,AVIF 通常比 WebP 再小 20~30%,但編碼慢很多、瀏覽器支援也稍晚。對我來說 WebP 已經把 4 MB 變成 400 KB,剩下那 100 KB 的優化不值得多一層複雜度。

小結

1
2
3
4
擔心的事   Cloudflare 額度 → 量完發現用不到 1%,完全是杞人憂天
真正的事 首屏 4 MB 圖片 → 手機讀者要等好幾秒
解法 WebP quality 82 → 省 91%,畫質看不出差異
副產品 原始檔移出 source/ → 進版控但不部署

兩個帶得走的原則:先量再擔心(我原本的焦慮完全放錯地方),以及量測的收穫常常在你要找的東西之外——我去查額度,結果找到一個效能問題。

如果你也在用 Hexo,這個部落格的建站流程留言系統統計功能Mermaid 圖表也都記錄過了。

Creative Commons 姓名標示 非商業性

本文採用 CC BY-NC 4.0 授權

歡迎轉載與引用,請標明出處(封面圖轉 WebP 省 91%:順便算清楚 Cloudflare Pages 的免費額度 — mur mur);禁止用於商業用途。

商業使用或合作提案,歡迎來信洽談:[email protected]

留言
分享

留言