ys memos

Blog

Next.jsのサイトでMarkdownのコードにSyntaxHighlightする


nextjs

2022/12/02


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

ブログを書く際にコードを掲載するが、コードのハイライトが無いとあまり見やすくならない。

そこで、コードにハイライトを適用させたので、その時の知見を記す。


自分の用いている環境などの前提は以下

  • MDX を使用
  • ローカルにある mdx を用い、SSG で静的サイトをビルドする構成

Prismを用いる。


Hashicorp 製の OSS であるnext-mdx-remoteを用いる。


next-mdx-remote のコードの呼び方に則って、サーバ側で行う MDX の変換をシリアライズと呼ぶ。 シリアライズの結果は HTML ではなく、フロントエンドで表示するために変換された形式である点は注意が必要。

Remark,Rehype 以外の処理フローがあるが、プラグインを設定したのはその2つだけのため、MDX が HTML になる間にそれらをどう通るのかを記す。

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

シンタックスハイライトのライブラリはこの内、Rehype のものである@mapboxrehype-prismを使う。


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

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';

MDX のコンパイルを行う。Markdown を HTML に変換するまでをコンパイルと呼ぶ例もあるかもしれないが、

pages/post/[slug].tsx
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: [],
      rehypePlugins: [rehypePrism],
    },
  });

  const source = { compiledSource };

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

サーバサイドでコンパイルされたcompiledSourceをフロントエンドで表示する。

pages/post/[slug].tsx
interface PostPageProps {
  source: MDXRemoteSerializeResult<Record<string, unknown>>;
}

const PostPage: NextPage<PostPageProps> = ({ source }) => {
  return <MDXRemote {...source} />;
};

@mapbox/rehype-prismは、コードブロックの要素に対してtoken function/ token punctuationなどのクラスを割り当ててくれるが、そのままではブラウザ上で色つけはできない。

そこで、各トークンに色をつける CSS をPrismからダウンロードし、_app.tsx(or _app.jsx)でimportする必要がある。

ダウンロードする際は、自分が使いたい言語や記法などをチェックした状態にし、テーマも好みのものを選ぶ。


シンタックスハイライトがあると、コードが一気にリッチになりますよね!


関連タグを探す