Astro 製のサイトで Markdown 内に書いた Mermaid のダイアグラムを描画する
2024/2/3
Tech
Astro 製のブログ (というか、ここ) で Mermaid のダイアグラムを描画したくなりました。
```mermaid
flowchart LR
Mermaid --> SVG
```
👆って書くと
👆ってなりたい。
JavaScript を消したい
せっかく Astro を使っているのでビルド成果物に Mermaid の JavaScript を含めたくない。 つまりビルドタイムで Mermaid のコードブロックを SVG に変換して HTML を出力したい。
実現手段の検討
Astro の組み込み機能
公式ドキュメント内には言及なし。 Issue で状況を確認してみると、Mermaid のシンタックスハイライトに関する issue はあった (Markdown mermaid is not supported #4433) けれど、Mermaid のコードをもとにダイアグラムを描画をする議論はなかった。
remark/rehype のプラグイン
Astro の markdown 機能は remark (と rehype) で構築されていてプラグインもサポートしているので、プラグインで Mermaid を描画出来ないか調べてみる。
temando/remark-mermaid
- 🥰 Mermaid 製の
mermaid.cli
を使っている - 🤔 肝心の
mermaid.cli
は deprecated
remcohaszing/remark-mermaidjs
- 🥰 (依存関係の remcohaszing/mermaid-isomorphic が) mermaid を実行している
- 🤔 mermaid が公開している API (
renderMermaid()
を使っていない- 依存関係の remcohaszing/mermaid-isomorphic は playwright でブラウザを起動しつつ、Mermaid の js を script tag で読み込ませている
southball/unist-remark-plugins - remark-mermaid
- 🥰 Mermaid 製の
mermaid-cli
を使って出力している - 🤔 mermaid が公開している API (
renderMermaid()
を使っていないchild_process.exec
で CLI を直接実行している
結論: mermaid-cli
を動かす plugin を自分で作る
多少気になることがあっても自分で実装しないのが一番幸せな気もするけれど、 Mermaid を実行する remark plugin を作って astro.config.ts で読み込むようにしました。TatsuyaYamamoto/t28.dev#64
- (1) Markdown 内の Mermaid のコードブロックを見つけて
- (2) Puppeteer の Browser インスタンスを作って
- (3) mermaid-cli が公開している
renderMermaid()
で Mermaid の描画を行って - (4) コードブロックを SVG要素を描画する html node で上書きする
export const mermaidRemarkPlugin: RemarkPlugin = () => {
return async (root) => {
// (1)
const mermaidCodeBlocks: MermaidCodeBlock[] = [];
// 超省略
// (2)
const browser = await puppeteer.launch({
headless: true,
});
await Promise.all(
mermaidCodeBlocks.map(async ({ code, index, parent }, blockIndex) => {
// (3)
const { data: svgBuffer } = await renderMermaidCli(
browser,
code.value,
"svg",
);
// 超省略
// (4)
parent.children[index] = svgNode;
}),
);
// 超省略
};
};