Mermaid 很方便:寫幾行文字,就能變成流程圖。問題是,如果每頁都把 Mermaid library 一起送到瀏覽器,讀者可能只是來看一篇文章,卻先搬一箱 JavaScript 回家。
文章中的流程圖、架構圖通常不需要訪客現場編輯或互動。這類圖適合用 Mermaid CLI 在建置前轉成靜態檔,再用 <img> 顯示——不用每頁載入 Mermaid JavaScript,Vite bundle 也不會因固定圖變胖,還能用 alt、width、height 和 <figcaption> 照顧可讀性與版面穩定。如果圖真的會跟著訪客操作即時變化,才保留瀏覽器端 Mermaid。
目錄
SVG、PNG,還是瀏覽器端 Mermaid?
先看圖的用途,不要先看工具名稱。選錯格式,就像拿海報字體去印名片:不是不能用,只是會有點委屈。
| 情境 | 建議 | 取捨 |
|---|---|---|
| 一般流程圖、架構圖 | build-time SVG | 線條與文字縮放清楚;仍要檢查文字大小與對比 |
| 固定像素圖片、社群分享、不想處理 SVG | build-time PNG | 瀏覽器處理單純;放大可能變糊,檔案也可能較大 |
| 圖會因操作即時改變 | 瀏覽器端 Mermaid | 保留互動,但要負擔下載、解析與執行 JavaScript |
| 想把圖直接放進 HTML | build-time inline SVG | 少一次圖片請求;HTML 變大,也要審查 SVG 內容 |
多數教學文章先選 SVG。若你的分享流程、圖片處理或內容系統更適合 PNG,也可以在同一次 build 產出 PNG。重點不是「PNG 永遠比較快」,而是不要讓每個頁面都執行整套繪圖 library。
若 Vite 出現 chunk 過大警告,先確認是不是 Mermaid 造成的。build.chunkSizeWarningLimit 預設 500 kB,只是警告門檻,調高只會讓終端機安靜,不會讓下載變快。固定圖改走 build-time 匯出;只有少數頁面需要互動圖時,再用 import('mermaid') 延遲載入並限制在需要的頁面。最後用 Network 和 Lighthouse 確認:不看圖的頁面,不應再載入 Mermaid chunk。
第一步:準備 Mermaid 原始檔
例如建立 src/diagrams/publish-flow.mmd:
flowchart TD
A[寫文章] --> B{檢查}
B -->|通過| C[Eleventy build]
B -->|未通過| A
C --> D[輸出靜態網站].mmd 是圖表的原始碼。它像食譜;SVG 或 PNG 才是端上桌的蛋糕。讀者通常只需要蛋糕,不需要一起下載烤箱。
第二步:用 Mermaid CLI 匯出 SVG 或 PNG
Mermaid 官方 CLI 的套件名稱是 @mermaid-js/mermaid-cli,命令名稱是 mmdc。可以全域安裝:
npm install -g @mermaid-js/mermaid-cli
mmdc -i "src/diagrams/publish-flow.mmd" -o "src/assets/diagrams/publish-flow.svg"
mmdc -i "src/diagrams/publish-flow.mmd" -o "src/assets/diagrams/publish-flow.png"或者裝在專案內,讓本機和 CI 使用同一套依賴:
npm install --save-dev @mermaid-js/mermaid-cli
./node_modules/.bin/mmdc \
-i "src/diagrams/publish-flow.mmd" \
-o "src/assets/diagrams/publish-flow.svg"mmdc 會依輸出副檔名產生 SVG、PNG 或 PDF。也可以在輸出時指定主題與透明背景:
mmdc -i input.mmd -o output.png -t dark -b transparent網站有深色模式時要多留意:SVG 能縮放,不代表它會自動換成深色配色。需要時在 build 時產生 light/dark 兩份,或固定一套在兩種背景都看得清楚的主題。
第三步:讓 Eleventy 複製圖檔並嵌入頁面
如果圖片放在 src/assets/diagrams/,在 eleventy.config.js 加入 passthrough copy:
export default function (eleventyConfig) {
eleventyConfig.addPassthroughCopy({
"src/assets/diagrams": "assets/diagrams"
});
}這會把來源目錄複製到輸出目錄的 assets/diagrams。接著,文章或模板可以用普通 HTML 顯示圖片:
<figure class="diagram">
<img
src="/assets/diagrams/publish-flow.svg"
alt="發布流程:寫文章後先檢查;通過才執行 Eleventy build,失敗則回到修改文章。"
width="900"
height="520"
loading="lazy"
decoding="async">
<figcaption>圖一:文章從檢查到 Eleventy build 的流程。</figcaption>
</figure>如果 Markdown 設定允許原始 HTML,直接放上面的 <figure> 即可。這裡要放的是 <img src="...">,不是 <div class="mermaid">。後者只是標記,仍需要 Mermaid JavaScript 在瀏覽器把它畫出來。
若 Markdown 會過濾 HTML,可改用 Nunjucks/WebC layout 或 shortcode 輸出同一段 HTML。不要為了繞過過濾器,就把所有內容無條件標成 safe。
alt 應描述讀者從圖中需要知道的結論或流程,不要只寫「流程圖」。如果正文已完整說明同一個流程,圖片可以用 alt="",避免螢幕閱讀器重複朗讀——但正文不能因此消失。不要只靠顏色區分成功與失敗;把差異寫在節點文字、箭頭標籤或正文裡。
第四步:讓圖片在手機上不拆台
圖片 CSS 可以先從這個版本開始:
.diagram {
max-width: 100%;
margin: 2rem 0;
}
.diagram img {
display: block;
width: 100%;
height: auto;
max-width: 100%;
}
.diagram figcaption {
margin-top: 0.5rem;
color: var(--muted, #666);
}width 和 height 要填輸出圖片的實際像素尺寸。瀏覽器可以先依比例保留空間,降低圖片載入時內容跳動;如果比例填錯,反而可能失真或預留錯誤空間。
寬流程圖在手機上常見兩種結果:
- 圖縮到看不清楚:改成較短的縱向流程。
- 圖不能再縮:提供原尺寸圖片連結,讓讀者自行放大查看。
如果有不同寬度或解析度版本,再考慮 <picture> 和 srcset。不要把一張超大 PNG 無條件送給所有裝置。
上線前檢查清單
- [ ]
.mmd與輸出的圖片都有納入版本控制,或 build 能穩定重建。 - [ ]
mmdc固定在專案 dev dependency,避免 CI 和本機產出不同。 - [ ] 輸出路徑與
<img src>在開發伺服器、正式站與子路徑部署都正確。 - [ ] Light/dark mode 下文字與背景都有足夠對比。
- [ ] build 後確認不看圖的頁面沒有載入 Mermaid chunk。
結語
固定圖先匯出,互動圖才在需要時載入 Mermaid。下一次新增 Mermaid 圖時,用 mmdc 產出 SVG 或 PNG,放進 Eleventy 的 passthrough asset,再用帶有 alt、尺寸和圖說的 <figure> 顯示。先改一張圖,再看 build 與 Network 數據。
參考資料
- Mermaid CLI 官方 README — 官方 CLI 安裝、
mmdc參數,以及 SVG/PNG/PDF 輸出。 - Mermaid CLI 官方文件入口 — Mermaid CLI 文件入口。
- Eleventy Passthrough File Copy —
addPassthroughCopy的來源與輸出路徑。 - Vite Build Options —
chunkSizeWarningLimit的預設值與用途。 - MDN:
<figure>—figure、figcaption與語意結構。 - MDN:HTML images —
img、alt與圖片可及性。 - MDN:Understanding and setting aspect ratios — 圖片尺寸與版面空間預留。
