Skip to content

D2対応 & mermaidサーバーレンダリング - #185

Open
riiimparm wants to merge 21 commits into
developfrom
feature/d2-codeblock
Open

D2対応 & mermaidサーバーレンダリング#185
riiimparm wants to merge 21 commits into
developfrom
feature/d2-codeblock

Conversation

@riiimparm

@riiimparm riiimparm commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

変更内容

D2記法のコードブロックに対応。

  • サーバーサイドでd2コードブロックをSVGに変換
  • mermaidもサーバーサイドレンダリングに変更
  • package.json/pnpm-lock.yaml: @terrastruct/d2を追加

d2

スクリーンショット 2026-08-29 17 05 03

mermaid

スクリーンショット 2026-08-29 17 05 28
テスト用md(mermaid)
---
title: mermaidビルド時レンダリング検証用デモ
description: 'mermaidビルド時SVGレンダリング検証用の記事です。'
author: 'RiiiM'
tags: [Tech]
pubDate: '2026-08-29'
---

mermaidをd2と同じくビルド時にNode(puppeteer)上でSVGレンダリングし、d2と共通のクラス(diagram-container/diagram-frame)でサイジングされることを確認します。

## フローチャート

```mermaid
flowchart TD
  A[開始] --> B{条件分岐}
  B -->|Yes| C[処理A]
  B -->|No| D[処理B]
  C --> E[終了]
  D --> E
```

## シーケンス図

```mermaid
sequenceDiagram
  participant Client
  participant Server
  participant DB
  Client->>Server: リクエスト
  Server->>DB: クエリ
  DB-->>Server: 結果
  Server-->>Client: レスポンス
```

## 縦長のグラフ(高さ制約確認用)

```mermaid
flowchart TD
  A --> B --> C --> D --> E --> F --> G --> H --> I --> J --> K
```

## ガントチャート

```mermaid
gantt
  title プロジェクトスケジュール
  dateFormat  YYYY-MM-DD
  section 設計
  要件定義      :a1, 2026-01-01, 5d
  基本設計      :a2, after a1, 7d
  section 実装
  開発          :a3, after a2, 14d
  テスト        :a4, after a3, 7d
```

## 円グラフ

```mermaid
pie title 言語別コミット数
  "TypeScript" : 45
  "Astro" : 30
  "CSS" : 15
  "その他" : 10
```

テスト用md(d2用)
---
title: D2コードブロックのサイズ調整検証用デモ
description: 'D2コードブロックのサイズ調整検証用の記事です。'
author: 'RiiiM'
tags: [Tech]
pubDate: '2026-08-13'
---

D2コードブロックのサイズ調整検証用の記事です。デスクトップ幅では横幅80vw・縦幅90vhの制約でアスペクト比を保ったまま表示されることを確認します。

## 横長のD2図(幅80vw基準で収まるケース)

```d2
a -> b: 1
a -> c: 2
a -> d: 3
a -> e: 4
a -> f: 5
a -> g: 6
a -> h: 7
a -> i: 8
a -> j: 9
a -> k: 10
```

## 縦長のD2図(高さ90vh制約でスケールダウンされるケース)

```d2
a -> b
b -> c
c -> d
d -> e
e -> f
f -> g
g -> h
h -> i
i -> j
j -> k
```

## コンテナ(ネスト)の例

```d2
cell tower: {
  satellites: {
    shape: package
  }
  satellites -> transmitter
}

online portal: {
  ui: {
    shape: hexagon
  }
}

data processor: {
  storage: {
    shape: cylinder
    style.multiple: true
  }
}

cell tower.satellites -> data processor.storage: transmit
online portal.ui -> data processor.storage
```

## 多様なシェイプ+スタイルの例

```d2
person: {
  shape: person
}
cloud: {
  shape: cloud
}
queue: {
  shape: queue
}
db: {
  shape: cylinder
  style.multiple: true
}
important: {
  shape: hexagon
  style.fill: "#38bdf8"
  style.stroke: "#0f172a"
  style.shadow: true
}
flagged: {
  style.fill: "#22d3ee"
  style.double-border: true
}
cube: {
  label: 3D Box
  style.3d: true
  style.fill: "#38bdf8"
}

person -> cloud
cloud -> queue
queue -> db
db -> important
important -> flagged
flagged -> cube
```

## 接続線のスタイルバリエーションの例

```d2
a -> b: normal
a -> c: dashed {
  style.stroke-dash: 4
}
a -> d: thick {
  style.stroke-width: 5
}
a <-> e: bidirectional
```


```d2
direction: right

web: {
  shape: circle
  label: "Web Browser"
}

lb: {
  shape: hexagon
  label: "Load Balancer"
}

app1: "App Server 1"
app2: "App Server 2"
app3: "App Server 3"

db: {
  shape: cylinder
  label: "Database"
}

web -> lb
lb -> app1
lb -> app2
lb -> app3
app1 -> db
app2 -> db
app3 -> db
```

@terrastruct/d2 (ブラウザ向けWASM実装) をCDN経由で動的importし、
mermaidと同じパターンでd2コードブロックをSVGに変換するremarkプラグインを追加。

Shikiが"d2"言語を認識できずplaintextにフォールバックしてしまうため、
markdown.syntaxHighlight.excludeLangsでd2のみシンタックスハイライトを無効化。
コンテナにmax-width:80vw、SVGにwidth/height:auto + max-width:100%/max-height:90vhを
指定し、アスペクト比を保ったまま画面内に収まるようCSSのみで制約(img的なreplaced
element縮小に任せる)。1024px未満(モバイル)は従来通り制約なし。
横長/縦長のD2図を含む再現用記事。デスクトップ幅での80vw/90vh制約の
証跡として残す。
@terrastruct/d2のJS APIはthemeOverrides的なAPIを持たず、themeIDでは
mermaid側の配色(背景#0f172a/ボーダー#38bdf8/ライン#22d3ee/文字#e2e8f0)に
近いものが無かったため、D2のテーマシステムが付与する意味的クラス
(N1-N7, B1-B6, AA/AB1-5)をCSSで直接上書きしてmermaidと同じ配色にした。

また、高さ制約(max-height:90vh基準のスケールダウン)をデスクトップ限定の
メディアクエリの外に出し、モバイルでも常時適用されるようにした
(幅80vwの制約は引き続きデスクトップのみ)。

コンテナはmermaidと同様にflex+justify-content:centerで中央揃えにし、
Tailwindクラス文字列(purge対象外で効かない可能性がある)からinline
style指定に変更した。
connectionのfill-B1(矢印先端マーカーのpolygon)とstroke-B1(線本体の
path、fill="none")を同一セレクタでまとめてfill/strokeを両方
!important上書きしていたため、線本体のfill="none"が上書きされ、
閉じていないbezierパスがブラウザにより暗黙的に閉じられて塗りつぶされ、
扇状に複数エッジが出る図で特に目立つ太いリボン状の見た目になっていた。
fill-B1とstroke-B1を別々のセレクタに分離し、それぞれの役割(マーカー
の塗り/線の色)にのみ対応するプロパティを当てるよう修正。
@riiimparm riiimparm linked an issue Aug 13, 2026 that may be closed by this pull request
@riiimparm riiimparm self-assigned this Aug 14, 2026
@riiimparm
riiimparm requested a review from naoki-00-ito August 14, 2026 16:28

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@riiimparm
style指定を src/layouts/BlogLayout.astro に寄せれないかな
当たらなそうだったらこのままでもOK!

@riiimparm riiimparm Aug 22, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d2のあるページだけにstyle追加したいのでBlogLayoutには入れないかな。後述コメにてクライアントレンダリングやめるからstyle変わるかも
mermaidと統合したほうがいいのもそうだなぁ、BlogLayoutで統合できるかみてみる

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@naoki-00-ito ダークテーマ化やめてデフォルトテーマにしました。ダイアグラム用のリサイズをBlogLayout.astroに寄せた


try {
const { D2 } = await import(
"https://esm.sh/@terrastruct/d2@0.1.33"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cdnでなく、package.jsonで管理している @terrastruct/d2 使えないかな?

Suggested change
"https://esm.sh/@terrastruct/d2@0.1.33"
"@terrastruct/d2"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@terrastruct/d2による事前レンダリングに変更

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mermaidもcdnなのでテーマ合わせる意味でもこのブランチで一緒に直しちゃったほうがいいか

@riiimparm riiimparm Aug 29, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@naoki-00-ito cdnやめた! サーバーレンダリングをd2, mermaid双方で行うようにしました

配色・矢印修正の経緯を詳しく説明する長いコメントが多く、初見の
可読性を下げていたため、要点(何のためか)だけ残して簡潔にした。
機能・見た目の変更なし。
クライアント側でCDNからD2 WASMを読み込んでレンダリングしていたのを廃止し、
Node上の@terrastruct/d2でビルド時にSVGへ変換してpublic/images/blog/<slug>/に
保存する方式に変更。d2のD2クラスは同時に1リクエストしか処理できないため
逐次処理に統一し、worker_threadsも明示的にterminateする。

またprefetchAllとの組み合わせでdev起動時に画像404が発生する競合があったため、
出力先ディレクトリを事前削除せず上書き+処理完了後の孤児ファイル削除に変更した。
# Conflicts:
#	astro.config.mjs
#	pnpm-lock.yaml
強制的なダーク配色CSS上書きをやめ、D2ネイティブのthemeID:0(Neutral default)+
sketch:trueをrenderOptionsで指定する方式に変更。コンテナの背景色・paddingも
撤去し、画像サイズぴったりにフィットするようにした。デスクトップの最大幅は
80vw→60vw、最大高さは90vh→80vhに変更。
クライアント側でCDNからmermaid.jsを読み込んでレンダリングしていたのを廃止し、
puppeteer経由の@mermaid-js/mermaid-cli(renderMermaid)でビルド時にSVGへ変換して
public/images/blog/<slug>/に保存する方式に変更。d2と同じくthemeはmermaidの
デフォルトテーマを使用する。

d2/mermaid共通で使うコンテナ用CSS(サイジング・中央寄せ)は各remarkプラグインの
per-article style注入から、src/layouts/BlogLayout.astroのグローバルCSSに寄せ、
クラス名も.d2-container/.d2-diagramから.diagram-container/.diagram-frameへ
統一した。
mermaid本体のlook:'handDrawn'は図種によって効かないものがあった(gantt/pie等)
ため、レンダリング後のSVGをsvg2roughjs(rough.js)で後処理する方式に変更。
図種によらず一様に手描き風の揺らぎ・ハッチングが適用されるようになった。

mermaidはデフォルトでラベルをforeignObject(HTML)で描画しており、
svg2roughjsがそれを正しく手描き変換できず日本語ラベルが文字化けしていた。
htmlLabels:falseでネイティブSVGの<text>を強制することで解決した。
あわせてsvg2roughjsの出力(viewBoxを持たずwidth/height属性のみ)に
対応するようextractSize()にフォールバックを追加。
theme:'base'+themeVariablesで、mermaidの配色をD2の実際のパレット値
(fill-B4:#E3E9FD、stroke-B1:#0D32B2、fill-N1:#0A0F25等)に合わせた。
mermaid公式のtheming docsに載っている変数を参照し、フローチャート/
シーケンス図/ノート/円グラフ/状態遷移図など今回使用する図種に関連する
項目を網羅的に設定している。
コードを読めば分かる説明的コメント(JSDocヘッダー等)を削除し、
非自明な理由(競合回避・ライブラリ制約・フォント回避策など)の
説明だけ一行に簡潔化した。
@riiimparm riiimparm changed the title D2記法のコードブロックに対応 D2対応 & mermaidサーバーレンダリング Aug 29, 2026
@riiimparm riiimparm linked an issue Aug 29, 2026 that may be closed by this pull request
CIはpnpm install(non-frozen)でPrettier 3.9.6に解決される一方、
ローカルのlockfileは3.5.3に固定されており、バージョン差でformat:checkが
CIのみ失敗していた。prettierを3.9.6に上げて再フォーマットし一致させた。
@riiimparm

Copy link
Copy Markdown
Collaborator Author

フォーマットエラーだが #191 マージ後に解消予定

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

D2対応 mermaidのデフォルトテーマを変更

2 participants