西出正美です。有益なことや無益なことなどいろいろ書いています。

Next.jsでSSG時にRemarkでMermaidをSVGとして出力する

Next.jsでSSG時にRemarkでMermaidをSVGにして出力してみたいと思うこと、ありますよね。
僕はあるのですがネット上にあまり情報が無かったので自分用にメモです。

今回はremark-mermaidjsを使って実装しました。

このサイトではMarkdownをunifiedで扱っているのでremark-mermaidjsuseします。
remark-mermaidjsはGoogle Chromeを使ってMermaidをSVGにしているらしくexecutablePathでGoogle Chromeのパスを指定しなければならないようです。
このサイトはGitHub Actionsでビルドしているので、ubuntuのために/opt/google/chrome/google-chromeを指定しました。なお、ローカル環境でも自由に動かせるように.envにもGoogle Chromeへのパスを書くことにしました。

// @ts-ignore
import rehypePrism from '@mapbox/rehype-prism';
import rehypeKatex from 'rehype-katex';
import rehypeStringify from 'rehype-stringify';
import remarkGfm from 'remark-gfm';
import remarkMath from 'remark-math';
import remarkMermaid from 'remark-mermaidjs';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import { unified } from 'unified';

export const markdownToHtml = async (markdown: string) =>
  (
    await unified()
      .use(remarkParse)
      .use(remarkMath)
      .use(remarkGfm)
      .use(remarkMermaid, {
        launchOptions: {
          executablePath:
            process.env.GoogleChromeExecutablePath ?? // .env
            '/opt/google/chrome/google-chrome', // for GitHub Actions Ubuntu
        },
        svgo: false,
      })
      .use(remarkRehype, { allowDangerousHtml: true, footnoteLabel: '脚注' })
      .use(rehypePrism)
      .use(rehypeKatex)
      .use(rehypeStringify, { allowDangerousHtml: true })
      .process(markdown)
  )
    .toString()
    .replace(//g, process.env.baseUrl || '');

以下にサンプルを置いておきます。図がSVGになっていることがわかると思います。

Flowchart

```mermaid
flowchart LR

A[Hard] -->|Text| B(Round)
B --> C{Decision}
C -->|One| D[Result 1]
C -->|Two| E[Result 2]
```

Text
One
Two
Hard
Round
Decision
Result 1
Result 2

Sequence diagram

```mermaid
sequenceDiagram
Alice->>John: Hello John, how are you?
loop Healthcheck
    John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts!
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
```

BobJohnAliceBobJohnAliceloop[Healthcheck]Rational thoughts!Hello John, how are you?Fight against hypochondriaGreat!How about you?Jolly good!

Gantt chart

```mermaid
gantt
    section Section
    Completed :done,    des1, 2014-01-06,2014-01-08
    Active        :active,  des2, 2014-01-07, 3d
    Parallel 1   :         des3, after des1, 1d
    Parallel 2   :         des4, after des1, 1d
    Parallel 3   :         des5, after des3, 1d
    Parallel 4   :         des6, after des4, 1d
```

2014-01-062014-01-072014-01-072014-01-082014-01-082014-01-092014-01-092014-01-10Completed Parallel 1 Parallel 2 Active Parallel 3 Parallel 4 Section

Class diagram

```mermaid
classDiagram
Class01 <|-- AveryLongClass : Cool
<<Interface>> Class01
Class09 --> C2 : Where am I?
Class09 --* C3
Class09 --|> Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
class Class10 {
  <<service>>
  int id
  size()
}
```

Cool
Where am I?
«Interface»
Class01
int chimp
int gorilla
size()
AveryLongClass
Class09
C2
C3
Class07
Object[] elementData
equals()
«service»
Class10
int id
size()

Git graph

```mermaid
gitGraph
    commit
    commit
    branch develop
    commit
    commit
    commit
    checkout main
    commit
    commit
```

maindevelop0-b5e69341-528cd792-fdc8ce33-4d320ed4-1e2f53d5-e24b1dd6-bedabe5

State diagram

```mermaid
stateDiagram-v2
[*] --> Still
Still --> [*]
Still --> Moving
Moving --> Still
Moving --> Crash
Crash --> [*]
```

Still
Moving
Crash

Pie chart

```mermaid
pie
"Dogs" : 386
"Cats" : 85.9
"Rats" : 15
```

79%18%3%DogsCatsRats

Entity Relationship Diagram

```mermaid
erDiagram
    CUSTOMER ||--o{ ORDER : places
    ORDER ||--|{ LINE-ITEM : contains
    CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
```

CUSTOMERORDERLINE-ITEMDELIVERY-ADDRESSplacescontainsuses

User Journey diagram

```mermaid
journey
  title My working day
  section Go to work
    Make tea: 5: Me
    Go upstairs: 3: Me
    Do work: 1: Me, Cat
  section Go home
    Go downstairs: 5: Me
    Sit down: 3: Me
```

CatMe
Go to work
Go to work
Me
Make tea
Make tea
Me
Go upstairs
Go upstairs
MeCat
Do work
Do work
Go home
Go home
Me
Go downstairs
Go downstairs
Me
Sit down
Sit down
My working day

C4 diagram

```mermaid
C4Context
title System Context diagram for Internet Banking System

Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.")
Person(customerB, "Banking Customer B")
Person_Ext(customerC, "Banking Customer C")
System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.")

Person(customerD, "Banking Customer D", "A customer of the bank, <br/> with personal bank accounts.")

Enterprise_Boundary(b1, "BankBoundary") {

  SystemDb_Ext(SystemE, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")

  System_Boundary(b2, "BankBoundary2") {
    System(SystemA, "Banking System A")
    System(SystemB, "Banking System B", "A system of the bank, with personal bank accounts.")
  }

  System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.")
  SystemDb(SystemD, "Banking System D Database", "A system of the bank, with personal bank accounts.")

  Boundary(b3, "BankBoundary3", "boundary") {
    SystemQueue(SystemF, "Banking System F Queue", "A system of the bank, with personal bank accounts.")
    SystemQueue_Ext(SystemG, "Banking System G Queue", "A system of the bank, with personal bank accounts.")
  }
}

BiRel(customerA, SystemAA, "Uses")
BiRel(SystemAA, SystemE, "Uses")
Rel(SystemAA, SystemC, "Sends e-mails", "SMTP")
Rel(SystemC, customerA, "Sends e-mails to")
```

<<person>>Banking Customer AA customer of the bank, with personal bank accounts.<<person>>Banking Customer B<<external_person>>Banking Customer C<<system>>Internet Banking SystemAllows customers to view information about their bank accounts, and make payments.<<person>>Banking Customer DA customer of the bank, with personal bank accounts.<<external_system_db>>Mainframe Banking SystemStores all of the core banking information about customers, accounts, transactions, etc.<<external_system>>E-mail systemThe internal Microsoft Exchange e-mail system.<<system_db>>Banking System D DatabaseA system of the bank, with personal bank accounts.<<system>>Banking System A<<system>>Banking System BA system of the bank, with personal bank accounts.BankBoundary2[ENTERPRISE]<<system_queue>>Banking System F QueueA system of the bank, with personal bank accounts.<<external_system_queue>>Banking System G QueueA system of the bank, with personal bank accounts.BankBoundary3[boundary]BankBoundary[ENTERPRISE]UsesUsesSends e-mails[SMTP]Sends e-mails toSystem Context diagram for Internet Banking System

Mermaid記法なら簡単にグラフを書けて便利なので、どんどん使っていきたいと思います。

NISHIDEMASAMI.GITHUB.IO
NISHIDE, Masami

西出正美です。有益なことや無益なことなどいろいろ書いています。

©NISHIDE, Masami Some Rights Reserved