Vivliostyle (v8.16.0+) で mermaid.js の図を表示する
Vivliostyle で組版するときに、ドキュメント内に Mermaid.js による図のDSLを記述して、ビルド時にレンダリングして掲載したい、という需要は多々あると思う。これまでも、Vivliostyle 内で head タグで JavaScript を指定して defer で動かす、という方法はインターネット上でいくつか方法が紹介されていた。
ただし、これはローカルで Chromium を立ち上げるプレビュー時には上手く描画されても、PDF にビルドする際に上手くいかないことがある[1]。Mermaid.js のレンダリングが終わる前に vivliostyle-cli の内部で動く Playwright が PDF 出力を走らせてしまうためだ。
そこで使えるのが、v8.16.0 から使えるようになった、VFM 以外の unified プロセッサーを動作させられるという機能を使うと、意外と簡単に Mermaid.js の展開を実現できる。
vivliostyle-cli では、GitHub Flavored Markdown を Vivliostyle コミュニティが独自に拡張した VFM (Vivliostyle Flavored Markdown) という記法を採用しており、内部ではこの VFM ベースでのマークダウンから HTML への変換を行い、ブラウザでレンダリングしたウェブページから PDF を生成している。
ところで、markdown を AST[2] に変換して各種操作を行い HTML に変換するには、unified というエコシステムが便利である。便利である、というか、VFM も中身をたどれば実態は unified のプロセッサーなのだ。
上述のプルリクエストで追加した機能は、vivliostyle-cli の設定ファイルに unified プロセッサーの生成ロジックを記載すれば、VFM ではなく自らが指定したプロセッサーに差し替えて利用することができる、という拡張ポイントの導入だ。
unified エコシステム上で HTML の AST を操作するフレームワークは rehype という。rehype のプラグインとして rehype-mermaid というものがある。VFM の生成ロジックの中にこれを組み合わせたものをつくり、前述のプロセッサ差し替えの拡張ポイントからねじ込めば、やりたいことが実現できる。
import { VFM } from "@vivliostyle/vfm";
import rehypeMermaid from "rehype-mermaid";
export default {
// ... 中略
documentProcessor: (config, metadata) => {
return VFM(config, metadata)
.use(rehypeMermaid, {strategy: 'img-png'});
},
// ...後略
}
package.json
で "type": "module"
を指定するのをお忘れなく。rehype のプラグインもバージョンによっては ESM でしか提供されていないものも多いが、Vivliostyle の create-book
コマンドで生成されるコードベースは、現時点では ESM 指定がされていない。
VFM も unified のプロセッサなので、.use
メソッドが生えている。なので、これを使って最後の処理に rehype-mermaid をくっつけている。
あとは、原稿ファイルの中で mermaid 言語のコードブロックを書く。以下の記述は Mermaid.js のドキュメントから拝借してきたものを一部加工したものだ。
```mermaid
classDiagram
note "From Duck till Zebra"
Animal <|-- Duck
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
```
これを PDF 出力すると、以下のように展開されている事がわかる。padding や margin などは、各自調節されたし。
ここまでのコード例とビルド成果物のPDFは、以下の Sample Repository で公開している。
Discussion