ys memos

Blog

Next.jsのサイトのMarkdownにMermaid記法を導入する


nextjs

2022/12/02


Next.js を用いて本ブログを構築している。

Prismを用いてコードブロックのシンタックスハイライトをしているのだが、Mermaid 記法をチェックしていてもそれが反映されないようであった。


生成された HTML を見ると、Mermaid コードブロックも他のコードブロック同様、token ...クラスが割り当てられていた。どうやらシンタックスハイライトは、Mermaid 記法をグラフ表示するのではなく Mermaid 記法のシンタックスをハイライトしてくれるもののようだ。


ここで記した流れで MDX がシリアライズされる内、コードブロックへの Prism による変換は rehype で行っているため、remark プラグインでmermaid.jsの求める形に MDX を変換してしまえばよい。

例えば、以下のコードブロックを

```mermaid
flowchart LR
  MDX/Markdown ==> Remark ==> Rehype
```

以下のように変換する。

<div class="mermaid">flowchart LR MDX/Markdown ==> Remark ==> Rehype</div>

MDX→HTML へのフローは以下のようになる。

flowchart LR MDX ==> mermaid記法をdivに書き換え ==> ... ==> HTML

ここにパッケージを作った。

リポジトリはこちら


pages/post/[slug].tsx
import * as fs from 'fs';
import * as path from 'path';

import mermaid from 'mermaid';
import { MDXRemote, MDXRemoteSerializeResult } from 'next-mdx-remote';
import rehypePrism from '@mapbox/rehype-prism';
import matter from 'gray-matter';
import { serialize } from 'next-mdx-remote/serialize';
import remarkMermaid from '@ysuzuki19/remark-mermaid';

export const getStaticProps: GetStaticProps = async ({ params: { slug } }) => {
  const filepath = path.join('..', 'posts', `${slug}.mdx`);
  const file = fs.readFileSync(filepath);

  const { content } = matter(file);
  const { compiledSource } = await serialize(content, {
    mdxOptions: {
      remarkPlugins: [remarkMermaid],
      rehypePlugins: [rehypePrism],
    },
  });

  const source = { compiledSource };

  return {
    props: {
      source,
    },
  };
};

interface PostPageProps {
  source: MDXRemoteSerializeResult<Record<string, unknown>>;
}

const PostPage: NextPage<PostPageProps> = ({ source }) => {
  React.useEffect(() => {
    mermaid.init()
  }, [])
  return <MDXRemote {...source} />;
};

getStaticProps()で SVG を生成しているわけではないので、mermaid.init()が必要。


mermaid 記法を導入したことによって、ブログに載せるアーキテクチャやフローチャートを画像を使うことなくコードで表現できるようになったのでかなり便利!

パッケージは、SSG 前提のためmermaid.init()をフロントで書くようにしていたが、将来的にはgetStaticProps()内で SVG を生成するようにしたい。


関連タグを探す