mermaid記法の図を描画する
2024年10月11日

mermaid記法の図を描画する

2,706文字(読了まで約7分)
headerimage

ブログ記事を書くにあたり、ちょっとした図を書くのに

  • diagrams.net で絵を書いて
  • ファイル出力して
  • mdx 内で引用する

という手順を取るのがめんどくさい。

mermaid 記法であれば、mdx 内に文字列で記述した内容が図として表示されるため、管理が非常に楽になる。

今回、このブログに mermaid を導入したい。

調べると mermaid から図を生成する方法として、どうも puppeteer や playwright を利用しているケースがあるようだったが、当ブログは cloudflare にデプロイしており、それらの重たいライブラリを配置することはできない。

このため、ここではクライアント側の処理に任せることにします。 hono でクライアントサイド処理を行うとなると、islands としてコンポーネントを定義することが考えられますが、特段、ユーザー操作にインタラクティブな処理を行いたいわけでもありませんので、ここでは、

  • mermaid.js をクライアント側で取得
  • mermaid 記法のデータを、クライアント側の mermaid で整形表示

させることを考えます。

ダークテーマ設定で端末の設定を取得したのと同様のやり方が取れます。

Hono のメイン処理である server.ts に今回自作する middleware の設定をします。 /posts/*を指定し、ブログ投稿記事のみに適用するようにします。 ※HonoX として createApp する前に、基礎となる app(baseとしています)を作成し、  baseに対して use により middleware を設定する必要があります。

/app/server.ts
import { showRoutes } from "hono/dev";
import { createHono } from "honox/factory";
import { createApp } from "honox/server";
import { themeRoute } from "./routes/theme";
import { embedClientThemeHandler } from "./hono-middleware/embedClientThemeHandler";
import { embedMermaid } from "./hono-middleware/embedMermaid";
 
// createApp前にベースとなるappを用意し、middlewareを設定する
const base = createHono();
 
base
  .use("*", embedClientThemeHandler)
  .use("/posts/*", embedMermaid) // 自作のembedMermaidミドルウェアを追加
  .route("/theme", themeRoute);
 
const app = createApp({ app: base });
 
showRoutes(app);
 
export default app;

embedMermaidは、Hono の Middleware として実装します。 route で処理されて応答する直前の html レスポンスに対し、mermaid 関係の処理を script タグで追加します。

/app/hono-middleware/embedMermaid.ts
import { createMiddleware } from "hono/factory";
 
export const embedMermaid = createMiddleware(async (c, next) => {
  await next();
 
  // レスポンスがHTMLでない場合は何もしない
  if (!c.res.headers.get("content-type")?.includes("text/html")) {
    return;
  }
 
  // レスポンスボディを取得
  let html = await c.res.text();
 
  // 追加するスクリプト
  const script = `
    <script type="module">
      import mermaid from 'https://unpkg.com/mermaid@10/dist/mermaid.esm.min.mjs';
      mermaid.initialize({ startOnLoad: true, theme:"dark" });
    </script>
`;
 
  // </head>タグの直前にスクリプトを挿入
  html = html.replace("</head>", `${script}</head>`);
 
  c.res = c.html(html);
});

mdxでの記述例
<div class="mermaid">graph TD; A-->B; A-->C; B-->D; C-->D;</div>

実際の表示は以下の通り

graph TD; A-->B; A-->C; B-->D; C-->D;

本ブログ記事中で mermaid 記法の図を表示できるようにしました。

  • Cloudflare Pages で重いライブラリを避けるため、クライアント側で描画させました
  • Hono の middleware として、mermaid.js の初期化処理をブログ記事のレスポンスに埋め込みました
  • mdx 内では、mermaid クラスを指定した要素で図が描画されるようになりました

以上です。

- コメント -

    このサイトではcookieを利用して、サイト訪問者の識別に利用します。 cookieの利用に同意いただくことで、サイト訪問者は記事のいいね機能等をご利用いただけます。 なお、サイト運営者はアクセス統計としてcookieの情報を利用する場合があります。