Next.jsでSSG時にRemarkでMermaidをSVGにして出力してみたいと思うこと、ありますよね。
僕はあるのですがネット上にあまり情報が無かったので自分用にメモです。
今回はremark-mermaidjs
を使って実装しました。
このサイトではMarkdownをunified
で扱っているのでremark-mermaidjs
をuse
します。
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になっていることがわかると思います。
```mermaid
flowchart LR
A[Hard] -->|Text| B(Round)
B --> C{Decision}
C -->|One| D[Result 1]
C -->|Two| E[Result 2]
```
```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!
```
```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
```
```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()
}
```
```mermaid
gitGraph
commit
commit
branch develop
commit
commit
commit
checkout main
commit
commit
```
```mermaid
stateDiagram-v2
[*] --> Still
Still --> [*]
Still --> Moving
Moving --> Still
Moving --> Crash
Crash --> [*]
```
```mermaid
pie
"Dogs" : 386
"Cats" : 85.9
"Rats" : 15
```
```mermaid
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
```
```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
```
```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")
```
Mermaid記法なら簡単にグラフを書けて便利なので、どんどん使っていきたいと思います。