概要
本ブログで使用しているSyntaxHighlighter(react-syntax-highlighter)からモダンなShikiへの移行について、ポイントとなる部分を記録として残します。
Next.js(App Router)でブログやドキュメントサイトを運用しているプロジェクト向けに、Shikiのサーバーコンポーネントを活用したシンタックスハイライトの実装方法やライトモード/ダークモード対応を説明します。
Shikiは、VS Codeでも使用されているTextMate文法やテーマを利用して高品質なシンタックスハイライトを提供するライブラリです。ShikiはサーバーサイドでコードをHTMLに変換するため、クライアント側のバンドルサイズを削減できます。また、クライアントサイドでの変換が不要で、パフォーマンスに優れた設計です。
Shikiでハイライトしたコード例です。見やすく、リロードしてもそのまま表示されます。
前提条件
本ブログはNext.js(App Router)を使用し、MDXによる記事管理を行っています。今回はMDX内のコードブロックに使用しているSyntaxHighlighterをShikiに置き換えます。
- Next.js 15.5.9 (App Router)
- React 19.0.0
- TypeScript 5
- MDX 3.1.0 (@mdx-js/loader 3.1.0, @mdx-js/react 3.1.0)
- Tailwind CSS 4.1.11
ShikiはNext.js以外にも、Astro・Vite・Nuxt・Remix・Gatsby・SvelteKitなど主要なフレームワークで利用できます。また、Rehype/Remarkプラグインとして任意のMDXパイプラインに統合することも可能です。
移行対象
react-syntax-highlighter を使用して動的にコードブロックをハイライトしていますが、Shikiに移行してサーバー側でHTMLを生成する形に変更します。
なぜShikiに移行するのか
Shikiの強みの1つはサーバー側レンダリング対応です。React Server ComponentでShikiを使用することにより、クライアント側のバンドルサイズを完全にゼロにできます。これにより、react-syntax-highlighterの150KBから98%削減できます。
さらに、VS Codeと同じTextMate文法による高精度なハイライト、多くのテーマサポート、CSS変数のみでのテーマ切り替えなど、品質とパフォーマンスの両面で優れた特徴を持っています。
MDXのコードブロックにShikiを組み込む
Shikiを組み込みます。サーバーコンポーネントとしてコードブロックを実装し、MDXと統合することでクライアントバンドルを使用せずにシンタックスハイライトを導入します。
Shikiのインストール
Shikiをプロジェクトにインストールします。
CodeBlockコンポーネントの作成
コードブロック用のサーバーコンポーネントを作成します。Shikiの公式ドキュメントでは、codeToHtmlを使った実装が推奨されています。
MDXとの統合
MDXProviderで先ほど作成したCodeBlockコンポーネントを使用するように設定します。
これでMDX内のコードブロックが自動的にShikiでハイライトされます。
例えば、以下のようにコードブロックを記述した場合
このように美しくハイライトされます。
テーマ設定(ライト/ダークモード対応)
Shikiのデュアルテーマ機能を使うことで、JavaScriptなしでライトモード・ダークモードの切り替えを実現できます。
オプションのdefaultColor: falseを設定すると、ShikiはCSS変数(--shiki-lightと--shiki-dark)を生成します。
これらの変数を使ってテーマを切り替えるには、global.cssに以下のスタイルを追加します。
テーマ切り替えの仕組み
ShikiはdefaultColor: falseを設定すると、生成するHTMLの各要素に--shiki-lightと--shiki-darkの両方のCSS変数をインラインスタイルとして埋め込みます。
つまり、すべての色情報が最初からHTMLに含まれているため、CSSで「どちらの変数を使うか」を切り替えるだけでテーマが変わります。JavaScriptによる再レンダリングや色の再計算は不要です。
もしくは、メディアクエリでシステムのテーマ設定に応じて切り替えることもできます。
この設定により、ユーザーのテーマ設定(ライト/ダーク)に応じてコードブロックのテーマが自動的に切り替わります。JavaScriptで処理する必要がなく、実装が簡潔です。
まとめ
Shikiを活用することでVS Code同等のハイライトを実現しながら、クライアントバンドルサイズをゼロにできました。テーマ管理はCSS変数のみで完結し、JavaScriptによる動的な切り替えも不要です。パフォーマンスとユーザー体験を両立できる良い仕組みだと思います。
Next.js(App Router)でMDXを使用しているプロジェクトでは、Shikiの導入によってシンタックスハイライトの最適化を実現できます。
