mermaid.jsに対応した

2020-02-29#meta#gatsby

追記

デプロイしてから分かったけど、production buildのみ図の描画がうまくいったりいかなかったりする。リロードしてみるとたまに表示できる。よくわからないので、SSRでの実装にするかも。


markdownみたいなかんたんな記法でフローチャートなどの図を描けるmermaid.jsをこのブログでサポートした。

たとえばこんな感じ。

graph TD
  client
  lb[alb]
  app1[rails]
  app2[rails]
  db[mysql]
 
  client --> lb --> app1 & app2 --> db

この図はこんなcode blockで書いている(エスケープだけしてある)。

\```mermaid
graph TD
  client
  lb[alb]
  app1[rails]
  app2[rails]
  db[mysql]
 
  client --> lb --> app1 & app2 --> db
\```

mermaid.jsをgatsbyで動かす

mermaid.jsはブラウザ上じゃないと動かすことができないため、gatsbyで動かすには

  1. クライアントサイドで動かす
  2. headless browserを利用してSSRする

の2通りしかない。

今回はより簡単にクライアントサイドで動かすようにした。既存のgatsby-remark-mermaidプラグインは後者を採用していてpuppeteerをつかっていた。ただ、試してみたところ自分の環境では動かなかったため、自作することにした。

Gatsbyで生成しているページはReactのコンポーネントでできているので、componentDidMountcomponentDidUpdateのようなタイミングでmermaidを動かしている。

import mermaid from "mermaid";
 
class PostTemplate extends Component {
  componentDidMount() {
    const element = document.getElementById("mermaid");
 
    mermaid.initialize({ startOnLoad: true });
    mermaid.mermaidAPI.render("container", "graph TD\n  a --> b", svg => {
      element.innerHTML = svg;
    })
  }
}

あとは、remarkプラグインを書いて、mermaidがついたcode blockを<div class="mermaid"></div>で囲うように変換するようにした。

const visit = require("unist-util-visit");
 
module.exports = ({ markdownAST }, pluginOptions) => {
  visit(markdownAST, "code", node => {
    if (node.lang !== "mermaid") return;
 
    node.type = "html";
    node.value = `<div class="mermaid">\n${node.value}\n</div>`;
  });
 
  return markdownAST;
};