Next.jsのブログにシンタックスハイライトを追加する

2024年7月1日
Next.jsのブログにシンタックスハイライトを追加する

このサイトは、Next.jsでブログ記事機能を作っていて、 ブログの記事はmdxファイルで作成し、マークダウンをベースに、一部Reactコンポーネントを読み込むことで記事を作成している。

今回、開発ノートというカテゴリを作って、開発関連のメモをこちらにまとめていくことにした。 その際、シンタックスハイライトが適用されるようにしたので、その方法をメモしておく。

インストール

シンタックスハイライトを実現するために、react-syntax-highlighterというライブラリを使用する。

https://github.com/react-syntax-highlighter/react-syntax-highlighter

Next.jsのプロジェクトに以下のコマンドで追加する。

npm install react-syntax-highlighter --save
npm install @types/react-syntax-highlighter --dev

設定

Next.jsでMDXを使用する際、mdx-components.tsxファイルで、 MDXコンテンツ内のHTML要素やコンポーネントをカスタマイズすることができる。

mdx-components.tsxファイルに以下の内容を追加した。

import type { MDXComponents } from 'mdx/types'
import Image from 'next/image'
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism"; // ①

export function useMDXComponents(components: MDXComponents): MDXComponents {
  return {
    ...components,
    pre: ({ children }) => <>{children}</>, // ②
    code: ({ className, children, ...rest }) => { // ③
      const match = /language-(\w+)/.exec(className || "");
      return match ? (
        <SyntaxHighlighter language={match[1]} style={oneDark}>
          {String(children)}
        </SyntaxHighlighter>
      ) : (
        <code {...rest} className={className}> // ④
          {children}
        </code>
      );
    },
  }
}

この設定により、マークダウン内のコードブロックが自動的にシンタックスハイライトされる。

解説

  1. prismのoneDarkスタイルを使用している。
  2. mdxのコードブロックは<pre><code>...</code></pre>の構造になるが、SyntaxHighlighterがpre要素込みのHTMLを生成するため、pre要素は削除して二重にならないようにしている。
  3. code要素では、言語名が取得できた場合は、SyntaxHighlighterを適用している。
  4. コードブロックで言語が指定されない場合や、インラインコードの場合は、通常のcode要素として表示する。