
【2026年10月版】
AstroのMarkdownにPikchrの図を埋め込む:ビルド時のSVG変換
公開日: 2026/10/13
読了時間: 約 9分
私はPlantUMLやMermaidが好きで、ローカルではよく使っています。ただ、それらのUMLの図をこのAstroサイトへ載せるときは、図を直すたびに画像を書き出して差し替える必要があるのでやっていませんでした。またラスタライズした図では変更履歴が追えません。
そこで、この Astro サイトに Pikchr を導入し、Markdown から参照した図をビルド時に SVG へ変換する処理を実装しました。Pikchr は図をテキストで記述して SVG を生成します。Markdown から図を呼び出して Astro のビルドに組み込む部分は、このサイト向けに追加しました。
Pikchrとは
Pikchrは、SQLiteの作者D. Richard Hippが開発した、技術文書の図をテキストで書くための言語です。Pikchrの公式ソースには、既存のPIC実装のコードを参照せず、Hipp氏が新しく実装したと記されています。
SQLiteの公式ドキュメントでは、バージョン3.34.0以降の構文図をPikchrからSVGへ変換しています。 ボックス、線、矢印、ラベルと、その位置関係を記述するとSVGを生成でき、Markdownなどの文書へ埋め込む用途が想定されています。
次のように、図を構成する要素をテキストで定義します。
box "Rust組み込み" wid 1.5 ht 0.55
box "Python" at last box + (1.62,0) wid 1.5 ht 0.55
arrow down from first box.s
box "SQL" wid 4.2 ht 0.5図の座標、ラベル、色はテキストで記述するため、コードと同じように変更差分を確認できます。静的な構成図の.pikファイルはsrc/diagramsに置き、Gitで管理しています。
このサイトで表示しているPikchrの図
Alopex DB の製品ページに掲載している構成図です。
この図は、Alopex DB の機能ページと記事の両方から同じ.pikファイルを参照しています。一つの図を正本として、複数ページで共有できます。
SVG 生成も Astro の Markdown 処理に組み込みました。.pikを正本として管理し、npm run devとnpm run buildの両方で同じ処理を通して、各ページの HTML に SVG を埋め込みます。
Markdownから画像と同じ形で参照する
記事側では、通常のMarkdown画像と同じ記法を使います。画像URLの代わりに、pikchr:に続けてsrc/diagrams内の図の名前を書きます。
本文にPikchrのソースやHTMLを書く必要はありません。記事を書く側が指定するのは、図の名前と代替テキストです。
Astro は remark プラグインで Markdown 処理を拡張できます。この仕組みを使い、pikchr:記法を扱うサイト専用のremarkPikchrを実装しました。Pikchr が図の記述と SVG 生成を担い、Astro が拡張の仕組みを提供し、remarkPikchrが両者をつなぎます。
remarkプラグインでインラインSVGへ変換する
Astro の Markdown 設定には、既存のコードタイトル、読了時間、ターミナル動画の各プラグインと並べてremarkPikchrを登録しました。
markdown: {
processor: unified({
remarkPlugins: [
remarkCodeTitles,
remarkReadingTime,
remarkTerminalVideo,
remarkPikchr,
],
}),
},remarkPikchrは Markdown の構文木をたどり、段落内に一つだけ置かれたpikchr:画像を探します。図の名前からsrc/diagrams内の.pikファイルを読み、Pikchr の WebAssembly 版である固定バージョンのpikchr-wasmへ渡して SVG を生成します。
変換の中心は、Markdown の画像ノードを Pikchr が返した SVG の HTML ノードへ差し替える処理です。
const img = child.type === 'paragraph' && child.children?.length === 1
? child.children[0]
: undefined;
if (img?.type === 'image' && img.url?.startsWith('pikchr:')) {
const name = img.url.slice('pikchr:'.length);
jobs.push(renderDiagram(name, img.alt ?? '').then((svg) => {
node.children![i] = { type: 'html', value: svg };
}));
}変換後のページには、外部のSVGファイルを読むimg要素ではなく、<svg>そのものが入ります。ページのHTMLだけで図を表示でき、サイトのCSSから幅やダークモード時の色を調整できます。
サイトで使うための情報をSVGへ加える
pikchr-wasmが図の SVG を生成した後、サイトで表示・利用するための情報を加えます。
- Markdownの代替テキストをSVGの
aria-labelへ渡し、role="img"を付ける - 日本語版の図には、日本語を表示できるフォント候補を埋め込む
- 共通の
arch-diagramクラスを付け、記事と製品ページで同じ表示にする - 図の名前を英数字、ピリオド、ハイフン、アンダースコアに限定する
代替テキストはHTML属性へ入れる前にエスケープします。図の名前を制限しているのは、Markdownからsrc/diagrams以外のファイルを指定できないようにするためです。
日本語フォントとアクセシビリティ用の属性は、次の処理でSVGへ追加します。
svg = svg
.replace(
'<svg ',
`<svg class="arch-diagram" role="img" aria-label="${escapeAttr(alt)}" `,
)
.replace(
/(<svg[^>]*>)/,
`$1<style>text{font-family:${font};font-size:24px}</style>`,
);図ごとに用意するのは Pikchr のソースと代替テキストです。共通の表示属性や日本語フォントの処理は、プラグインにまとめています。
壊れた図はAstroのビルドで止める
Pikchrの構文に誤りがあると、pikchr-wasmはSVGの代わりにエラー文を返します。プラグインは出力が<svgから始まることを確認し、変換できなかった図が一つでもあればAstroのビルドを失敗させます。
let svg = await pikchr.render(source);
if (!svg.startsWith('<svg')) {
throw new Error(`Pikchr error in ${file}:\n${svg}`);
}これにより、開発中はnpm run devでエラーを確認でき、公開前にはnpm run buildが壊れた図を検出します。Pikchrのソースと表示結果が食い違ったまま公開される状態も避けられます。
動く図と静止した構成図で仕組みを分ける
アニメーション図にはStarch、静止した構成図には Pikchr を使っています。
Starch は読者のブラウザーで DSL を読み、再生位置に応じて SVG を書き換えます。再生、一時停止、シークなどの操作を提供するため、<animated-diagram>というカスタム要素で表示しています。
Pikchr の図は Astro のビルド時に SVG へ変換し、その SVG を読者のブラウザーへ渡します。Markdown では画像と同じ形で図を置けます。図の動きに合わせて、変換する場所と埋め込み方を使い分けています。
まとめ
このサイトでは、Pikchr で書いた構成図を Astro の Markdown から参照し、ビルド時にインライン SVG へ変換します。Pikchr が図を SVG にし、Astro のプラグイン機構が Markdown 処理への接続点を提供し、サイト専用の remark プラグインが両者をつないでいます。
- 図の正本は
src/diagramsの.pikファイルに置く - Markdownでは通常の画像記法と
pikchr:で図を指定する - remarkプラグインが
pikchr-wasmでSVGへ変換する - 代替テキスト、日本語フォント、共通クラスをSVGへ加える
- Pikchrの構文エラーはAstroのビルドで検出する
図を直してから公開ページへ反映するまでを、.pikの変更とAstroのビルドだけで完了できるようになりました。