D2対応 & mermaidサーバーレンダリング - #185
Conversation
@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を別々のセレクタに分離し、それぞれの役割(マーカー の塗り/線の色)にのみ対応するプロパティを当てるよう修正。
# Conflicts: # astro.config.mjs
There was a problem hiding this comment.
@riiimparm
style指定を src/layouts/BlogLayout.astro に寄せれないかな
当たらなそうだったらこのままでもOK!
There was a problem hiding this comment.
d2のあるページだけにstyle追加したいのでBlogLayoutには入れないかな。後述コメにてクライアントレンダリングやめるからstyle変わるかも
mermaidと統合したほうがいいのもそうだなぁ、BlogLayoutで統合できるかみてみる
There was a problem hiding this comment.
@naoki-00-ito ダークテーマ化やめてデフォルトテーマにしました。ダイアグラム用のリサイズをBlogLayout.astroに寄せた
|
|
||
| try { | ||
| const { D2 } = await import( | ||
| "https://esm.sh/@terrastruct/d2@0.1.33" |
There was a problem hiding this comment.
cdnでなく、package.jsonで管理している @terrastruct/d2 使えないかな?
| "https://esm.sh/@terrastruct/d2@0.1.33" | |
| "@terrastruct/d2" |
There was a problem hiding this comment.
@terrastruct/d2による事前レンダリングに変更
There was a problem hiding this comment.
mermaidもcdnなのでテーマ合わせる意味でもこのブランチで一緒に直しちゃったほうがいいか
There was a problem hiding this comment.
@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ヘッダー等)を削除し、 非自明な理由(競合回避・ライブラリ制約・フォント回避策など)の 説明だけ一行に簡潔化した。
CIはpnpm install(non-frozen)でPrettier 3.9.6に解決される一方、 ローカルのlockfileは3.5.3に固定されており、バージョン差でformat:checkが CIのみ失敗していた。prettierを3.9.6に上げて再フォーマットし一致させた。
This reverts commit 651357e.
|
フォーマットエラーだが #191 マージ後に解消予定 |
変更内容
D2記法のコードブロックに対応。
d2コードブロックをSVGに変換package.json/pnpm-lock.yaml:@terrastruct/d2を追加d2
mermaid
テスト用md(mermaid)
テスト用md(d2用)