DEV Community

Hama
Hama

Posted on • Originally published at beachone1155.vercel.app

技術ブログにMermaidダイアグラムを導入した話【はてなブログ・DEV.to・Next.js対応】

技術ブログにMermaidダイアグラムを導入した話【はてなブログ・DEV.to・Next.js対応】

はじめに

技術記事を書く時、フローチャートやシーケンス図があると格段に分かりやすくなりますよね。

今回、マルチプラットフォーム対応の技術ブログでMermaid記法によるダイアグラム表示に対応したので、その実装方法を紹介します!

対応したプラットフォーム:

  • 📝 はてなブログ - カスタムJavaScriptで対応
  • 🌐 DEV.to - Mermaidを画像に変換して投稿
  • Next.js(Vercel) - クライアントサイドレンダリング

Mermaidとは?

Mermaidは、テキストベースでダイアグラムを描けるJavaScriptライブラリです。

記述例:

graph TD
    A[ユーザー] -->|記事を書く| B[Markdown]
    B -->|変換| C[Mermaid]
    C -->|レンダリング| D[ダイアグラム表示]
Enter fullscreen mode Exit fullscreen mode

シンプルなテキストで、こんな感じの図が描けます。めっちゃ便利!

各プラットフォームの対応方法

1. はてなブログでの対応

はてなブログは標準でMermaidをサポートしていないため、カスタムJavaScriptで対応しました。

実装手順

1) はてなブログの管理画面で「設定」→「詳細設定」を開く

2) 「headに要素を追加」に以下を貼り付け:

<!-- Mermaidダイアグラムのスタイル設定 -->
<style>
  .mermaid {
    background-color: #ffffff !important;
    padding: 20px;
    border-radius: 4px;
    margin: 20px 0;
  }

  .mermaid svg {
    background-color: #ffffff !important;
  }
</style>

<!-- Mermaidダイアグラム表示用スクリプト -->
<script type="module">
  import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';

  document.addEventListener('DOMContentLoaded', function() {
    mermaid.initialize({
      startOnLoad: true,
      theme: 'default',
      themeVariables: {
        background: '#ffffff'
      },
      securityLevel: 'loose'
    });

    document.querySelectorAll('pre code').forEach((codeBlock) => {
      const codeText = codeBlock.textContent || codeBlock.innerText;

      if (codeText.trim().startsWith('mermaid')) {
        const pre = codeBlock.parentElement;
        if (pre) {
          const lines = codeText.split('\\n');
          const mermaidCode = lines.slice(1).join('\\n').trim();

          const mermaidDiv = document.createElement('div');
          mermaidDiv.className = 'mermaid';
          mermaidDiv.textContent = mermaidCode;

          pre.replaceWith(mermaidDiv);
        }
      }
    });

    mermaid.run({
      querySelector: '.mermaid'
    });
  });
</script>
Enter fullscreen mode Exit fullscreen mode

3) 記事では以下のように書く:

```


mermaid
graph LR
    A --> B


```
```

`

> [!IMPORTANT]
> はてなブログでは `

 ```mermaid ` という書き方ができないため、コードブロック内の最初の行に `mermaid` と書く必要があります。

#### ポイント

- ✅ **白背景を強制**: 暗い背景になる問題を解決
- ✅ **CDN経由**: 最新版のMermaidを自動で利用
- ✅ **一度設定すれば全記事に適用**

### 2. DEV.toでの対応

DEV.toは**Mermaidをネイティブサポートしていない**ため、画像に変換して投稿する方式を採用しました。

#### 実装(自動化)

Node.jsスクリプトで、記事投稿時に自動的にMermaidブロックを画像に変換します。

```

javascript
// scripts/utils/mermaid-converter.mjs
import { execSync } from 'child_process';

export async function convertMermaidToImage(mermaidCode, outputPath) {
    const tempInputFile = `/tmp/mermaid-${Date.now()}.mmd`;

    fs.writeFileSync(tempInputFile, mermaidCode, 'utf8');

    // mermaid-cliで画像変換(背景は白色)
    execSync(
        `npx -y @mermaid-js/mermaid-cli@latest -i "${tempInputFile}" -o "${outputPath}" -b white`,
        { stdio: 'inherit' }
    );

    fs.unlinkSync(tempInputFile);
    return true;
}


```

**変換の流れ:**
1. Markdown内の ` ```
{% endraw %}
mermaid {% raw %}` ブロックを検出
2. `{% endraw %}@mermaid-js/mermaid-cli{% raw %}`で画像(PNG)に変換
3. `{% endraw %}public/images/diagrams/{% raw %}`に保存
4. Markdownを `{% endraw %}![diagram](/images/diagrams/xxx.png){% raw %}` に置き換え

#### メリット

- ✅ DEV.toでも確実に表示される
- ✅ 画像なのでロード時間が速い
- ✅ ダークモードでも見やすい(白背景指定)

### 3. Next.js(Vercel)での対応

自サイト(Next.js)では、クライアントサイドでMermaidをレンダリングしています。

#### 実装

`{% endraw %}{% raw %}``tsx
// src/components/mdx/MermaidRenderer.tsx
'use client';

import { useEffect } from 'react';

export function MermaidRenderer() {
    useEffect(() => {
        async function initMermaid() {
            const mermaid = (await import('mermaid')).default;

            mermaid.initialize({
                startOnLoad: true,
                theme: 'default',
                themeVariables: {
                    background: '#ffffff', // ダークモードでも白背景
                },
                securityLevel: 'loose',
            });

            const codeBlocks = document.querySelectorAll('pre code.language-mermaid');
            codeBlocks.forEach((codeBlock, index) => {
                const pre = codeBlock.parentElement;
                if (pre) {
                    const code = codeBlock.textContent || '';
                    const wrapper = document.createElement('div');
                    wrapper.className = 'mermaid-diagram-wrapper';
                    wrapper.id = `mermaid-diagram-${index}`;
                    wrapper.textContent = code;
                    pre.replaceWith(wrapper);
                }
            });

            mermaid.run({
                querySelector: '.mermaid-diagram-wrapper',
            });
        }

        initMermaid();
    }, []);

    return null;
}
``{% endraw %}{% raw %}`

#### ダークモード対応(CSS)

`{% endraw %}{% raw %}``css
/* src/app/globals.css */
.mermaid-diagram-wrapper,
.mermaid-diagram-wrapper svg {
  background-color: #ffffff !important;
  padding: 20px;
  border-radius: 8px;
  margin: 20px 0;
}

/* ダークモードでは薄い枠線を追加 */
.dark .mermaid-diagram-wrapper {
  border: 1px solid #475569;
}
``{% endraw %}{% raw %}`

## 苦労した点と解決方法

### 問題1: 背景が暗くて見づらい

**症状:**
デフォルトのMermaidテーマだと、ダイアグラムの背景が暗い色になり、矢印や文字が見にくい。

**解決策:**
- `{% endraw %}themeVariables.background: '#ffffff'{% raw %}`で強制的に白背景に
- CSSで`{% endraw %}.mermaid{% raw %}`要素にも白背景を適用

### 問題2: ダークモードで真っ白すぎて浮く

**症状:**
ダークモードのページで白背景のダイアグラムが浮いて見える。

**解決策:**
`{% endraw %}{% raw %}``css
.dark .mermaid-diagram-wrapper {
  border: 1px solid #475569; /* 薄い枠線を追加 */
}
``{% endraw %}{% raw %}`

### 問題3: はてなブログで `{% endraw %} 
{% raw %}
```

mermaid ` が使えない

**症状:**
はてなブログはコードブロックの言語指定に対応していない。

**解決策:**
コードブロック内の最初の行を `mermaid` にして、JavaScriptで判定する方式に変更。

## まとめ

Mermaidダイアグラムを3つのプラットフォームで表示できるようにした実装を紹介しました。

**ポイント:**
- 📝 **はてなブログ**: カスタムJSで動的レンダリング
- 🌐 **DEV.to**: CLIで事前に画像変換
-**Next.js**: クライアントサイドレンダリング + ダークモード対応

各プラットフォームの特性に合わせた実装で、どこでも快適にダイアグラムが表示されるようになりました!

技術記事に図解を入れたい方の参考になれば嬉しいです 🎉

## 参考リンク

- [Mermaid公式ドキュメント](https://mermaid.js.org/)
- [Mermaid CLI](https://github.com/mermaid-js/mermaid-cli)
- [はてなブログのカスタマイズ](https://help.hatenablog.com/)

---

*この記事の図解もすべてMermaidで作成されています!*
Enter fullscreen mode Exit fullscreen mode

Top comments (0)