Mermaid 很方便:寫幾行文字,就能變成流程圖。問題是,如果每頁都把 Mermaid library 一起送到瀏覽器,讀者可能只是來看一篇文章,卻先搬一箱 JavaScript 回家。這篇的做法是:固定不變的圖在 build 時先匯出成 SVG 或 PNG,網頁只顯示普通圖片。

先講結論:固定圖在 build 時匯出

文章中的流程圖、架構圖通常不需要訪客現場編輯或互動。這類圖適合用 Mermaid CLI 在建置前轉成靜態檔,再用 <img> 顯示。

這樣做有三個好處:

  • 不用每頁載入 Mermaid JavaScript。
  • Vite bundle 不會因為固定圖而一起變胖。
  • 可以用圖片的 altwidthheight<figcaption> 照顧可讀性與版面穩定。

如果圖真的會跟著訪客操作即時變化,才保留瀏覽器端 Mermaid。互動不是免費的,通常會用 JavaScript 預算付款。

SVG、PNG,還是瀏覽器端 Mermaid?

先看圖的用途,不要先看工具名稱。選錯格式,就像拿海報字體去印名片:不是不能用,只是會有點委屈。

情境建議取捨
一般流程圖、架構圖build-time SVG線條與文字縮放清楚;仍要檢查文字大小與對比
固定像素圖片、社群分享、不想處理 SVGbuild-time PNG瀏覽器處理單純;放大可能變糊,檔案也可能較大
圖會因操作即時改變瀏覽器端 Mermaid保留互動,但要負擔下載、解析與執行 JavaScript
想把圖直接放進 HTMLbuild-time inline SVG少一次圖片請求;HTML 變大,也要審查 SVG 內容

多數教學文章先選 SVG。若你的分享流程、圖片處理或內容系統更適合 PNG,也可以在同一次 build 產出 PNG。重點不是「PNG 永遠比較快」,而是不要讓每個頁面都執行整套繪圖 library。

第一步:準備 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

第四步:讓圖片在手機上不拆台

圖片 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);
}

widthheight 要填輸出圖片的實際像素尺寸。瀏覽器可以先依比例保留空間,降低圖片載入時內容跳動;如果比例填錯,反而可能失真或預留錯誤空間。

寬流程圖在手機上常見兩種結果:

  • 圖縮到看不清楚:改成較短的縱向流程。
  • 圖不能再縮:提供原尺寸圖片連結,讓讀者自行放大查看。

如果有不同寬度或解析度版本,再考慮 <picture>srcset。不要把一張超大 PNG 無條件送給所有裝置。

alt 不要只寫「Mermaid 圖」

alt 應該描述讀者從圖中需要知道的結論或流程,例如「通過才執行 Eleventy build,失敗則回到修改文章」,而不是只寫「流程圖」。

如果正文已經完整說明同一個流程,圖片可以使用 alt="",避免螢幕閱讀器重複朗讀。但正文不能因此消失。圖表不是把文字藏起來的魔法斗篷。

<figure> 讓圖片成為一個有語意的內容單位,<figcaption> 則提供看得見的圖說,也能成為父層 <figure> 的 accessible name。不要只靠顏色區分成功與失敗;把差異寫在節點文字、箭頭標籤或正文裡。

Vite 顯示 chunk 過大,應該怎麼判斷?

Vite 的 build.chunkSizeWarningLimit 預設是 500 kB。這是警告門檻,不是超過就會壞掉的硬限制;把數字調大,只會讓終端機比較安靜,不會讓下載速度變快。

可以用這張表判斷:

你遇到的情況合理處理
固定 Mermaid 圖,文章不需要互動build-time 匯出 SVG/PNG,頁面只載入圖片
只有少數頁面需要互動圖import('mermaid') 延遲載入,並限制在需要的頁面
chunk 已經量測過,大小可接受,只是不想看到警告調高 warning 門檻,但不要把它當效能修復
想改善快取與分組使用手動切 chunk;它不會消除 Mermaid 的下載與執行成本

最後要看實際結果:檢查 build 後不看圖的頁面是否還載入 Mermaid chunk,再用瀏覽器 Network、Lighthouse 和行動裝置測試。警告是煙霧警報器,不是火災報告;先找煙從哪裡來。

上線前檢查清單

  • [ ] .mmd 與輸出的圖片都有納入版本控制,或 build 能穩定重建。
  • [ ] mmdc 固定在專案 dev dependency,避免 CI 和本機產出不同。
  • [ ] 輸出路徑與 <img src> 在開發伺服器、正式站與子路徑部署都正確。
  • [ ] 圖片有描述性 alt,需要時補上 <figcaption> 和正文文字版。
  • [ ] widthheight 與 responsive CSS 已設定。
  • [ ] Light/dark mode 下文字與背景都有足夠對比。
  • [ ] 手機實機看得懂;太寬時提供原圖連結或拆成多張圖。
  • [ ] build 後確認不看圖的頁面沒有載入 Mermaid chunk。

推薦工具/資源

  • Mermaid CLI:適合固定流程圖、架構圖,想在 build 時產生 SVG/PNG 的站長。
  • Eleventy passthrough copy:適合把已產生的圖片穩定複製到輸出目錄。
  • 瀏覽器 Network 與 Lighthouse:適合確認「真的變快了」,而不是只讓 Vite 警告消失。

結語:先把固定圖搬到 build 時間

固定圖先匯出,互動圖才在需要時載入 Mermaid。這個分工通常比「每頁都準備一套繪圖工具」更省事,也更符合靜態網站的個性。

下一次新增 Mermaid 圖時,可以先做一件事:用 mmdc 產出 SVG 或 PNG,放進 Eleventy 的 passthrough asset,再用帶有 alt、尺寸和圖說的 <figure> 顯示。先改一張圖,再看 build 與 Network 數據;咖啡可以慢慢喝,bundle 不必慢慢胖。

參考資料