Rehype Pretty Codeを使いこなす 第1回 導入とコードブロックのスタイリング

シンタックスハイライトを実現するRehype Pretty Codeを紹介します。第1回目はAstroプロジェクトへのRehype Pretty Codeの導入と、コードブロックの基本的なスタイリングについて解説します。

発行

著者 菅野 亜実 フロントエンド・エンジニア
Rehype Pretty Codeを使いこなす シリーズの記事一覧

はじめに

技術系のコンテンツでは、本文中にソースコードを掲載する機会が多くあります。そして、MarkdownやMDXを利用してコンテンツを管理している場合も多いと思います。

Markdown記法を使うと、コードブロックもシンプルに書くことができます。

コードブロックを表示するMarkdown記法

```js
console.log("Hello World!")
```

しかし、次のようなカスタマイズは、Markdown記法のみで実現することは困難です。

  • シンタックスハイライト(トークンごとの色分け)によって見やすく表示したい
  • 行番号を表示したい
  • タイトルやキャプションを添えたい
  • 特定の行(もしくは単語)にのみ注目させたい

補足:トークン

この記事で言及する「トークン」とは、ソースコードの文字列を、そのプログラミング言語で意味を持つ最小単位に分けたものを指します。たとえば、JavaScriptのconst a = 100;というコードは、consta=100;という5つのトークンに分けられます。

本シリーズでは、Markdownのシンプルさはそのままに、このようなコードブロックのカスタマイズを実現するライブラリ「Rehype Pretty Code」をご紹介します。

Rehype Pretty Codeの特長

Rehype Pretty Codeは、shikiをベースとしたシンタックスハイライト機能に加え、コードブロックを表現豊かにするさまざまなMarkdown拡張記法を提供するライブラリです。

特長1. ビルド時にHTMLを加工する

Rehype Pretty Codeはrehypeプラグインとして動作します。rehypeプラグインとは、簡単に言えばMarkdownやMDXから生成されたHTMLを加工するライブラリです。

補足:rehypeプラグイン

rehypeプラグインに関して詳しく学びたい方には、次のシリーズをおすすめします。

そのため、Next.jsやAstroなど、MarkdownやMDXでコンテンツを管理するサイトジェネレーターに簡単に導入でき、ビルドの段階でシンタックスハイライトを適用したHTMLを生成します。クライアント側で動的なDOMの書き換えが行われることはありません。

特長2. スタイルはフルカスタマイズ可能

Rehype Pretty Codeは、インラインスタイルとしてトークンに色を適用するだけで、ライブラリ独自のCSSを提供しません。

色以外のスタイルについては、Rehype Pretty Codeが追加したdata属性をセレクタとして、自分でスタイルを指定できます。

特長3. 独自機能を追加できる

Rehype Pretty Codeでは、Visitor Hooksというオプションを利用することで、独自のHTML加工処理を挟みこむことができます。

たとえば、#A1EEBDなどといった色を表すコードが登場したときに、そのコードがどんな色を表すのかを示すプレビューを追加する、ということも可能です。本シリーズの後半では、この色プレビュープラグインを例に、Visitor Hooksの活用法も解説します。

Astroによるハンズオン

このシリーズでは、AstroでのWebサイト開発を例に、Rehype Pretty Codeの活用方法を解説していきます。

実際にRehype Pretty Codeを導入するところからハンズオン形式で学びたい方は、デモリポジトリのmainブランチのコードから始めてください。

Astroを触ったことがない、という方は、次のシリーズを一読しておくとスムーズにハンズオンを楽しめるでしょう。

とはいえ、Next.jsであっても、使い方は大きく変わりません。Astroと異なる点は、適宜補足していきます。

その他のサイトジェネレーターなどで使いたい場合は、サイトジェネレーターのドキュメントでrehypeプラグインの設定方法を調べるか、Rehype Pretty CodeドキュメントのUsageを参考にしてください。

サイトジェネレーターに導入する

AstroとNext.jsでは、導入手順はほとんど同じです。

  1. npmなどでrehype-pretty-codeshikiを合わせてインストール
  2. configファイルのrehypeプラグインオプションにrehype-pretty-codeを追加

以下に、Astroのconfigファイル(astro.config.mjs)の例を示します。

Astroに導入する場合:astro.config.mjsの例

import { defineConfig } from 'astro/config'
// rehype-pretty-codeからrehypeプラグインをimport
import rehypePrettyCode from 'rehype-pretty-code'

/** @type {import('rehype-pretty-code').Options} */
const prettyCodeOptions = {
  /** これから追加していく */
}

export default defineConfig(
  /** @type {import('astro').AstroUserConfig} */ {
    markdown: {
      // Astroビルドインのシンタックスハイライト機能を無効化
      syntaxHighlight: false,
      // 代わりにRehype Pretty Codeを使う
      rehypePlugins: [
        // [plugin, option] という書式
        [rehypePrettyCode, prettyCodeOptions]
      ],
    },
  }
)

rehype-pretty-codeからimportしたものを、markdown.rehypePluginsに追加しています。

prettyCodeOptionsはRehype Pretty Codeに渡すオプションです。今は空オブジェクトとし、これから設定を追加していきましょう。

Astroの場合は、デフォルトでシンタックスハイライト機能が搭載されているため、markdown.syntaxHighlightfalseを指定して、デフォルトの機能を無効化しておくのがポイントです。

Next.jsでの設定方法は、Rehype Pretty Codeのドキュメントにあるnext.config.mjsの例を参考にしてください。

この章で行った作業内容の差分は、以下から確認できます。

コードブロックから生成されるHTML

ここまでの設定だけで、MarkdownやMDXファイル内のコードブロックを、自動的にRehype Pretty Codeが加工してくれるようになっています。

どのようにシンタックスハイライト表示されているか、例を見てみましょう。

ハンズオン

現時点でのコード全体は、デモリポジトリのdemo-1-default-viewブランチにあるので、実際に動作を見てみるのもおすすめです。

インストールとサーバー起動

npm install
npm run astro dev

たとえば、次のようなMarkdownを考えます。

Markdownによるコードブロック

```js
console.log("Hello World!")
```

このコードブロックは、次のように表示されます。

また、この部分のHTMLは、次のような構造になっています。

ビルド後のHTML

<figure data-rehype-pretty-code-figure>
  <pre style="background-color:#22272e;color:#adbac7" tabindex="0" data-language="js" data-theme="github-dark-dimmed">
    <code data-language="js" data-theme="github-dark-dimmed" style="display: grid;">
      <span data-line>
        <span style="color:#ADBAC7">console.</span>
        <span style="color:#DCBDFB">log</span>
        <span style="color:#ADBAC7">(</span>
        <span style="color:#96D0FF">"Hello World!"</span>
        <span style="color:#ADBAC7">);</span>
      </span>
    </code>
  </pre>
</figure>

style属性によって、背景色(background-color)や、各トークンごとに異なる文字色(color)が直接設定されていることがわかります。

Rehype Pretty Codeが生成するHTML構造

一般に、Rehype Pretty Codeは、コードブロックを次のような構造のHTMLに置き換えます。

HTMLの構造

[data-rehype-pretty-code-figure]
  > pre
    > code
      > [data-line]
        > トークンごとのspan

そして、pre要素とcode要素には、次の属性が付与されています。

  • data-language: Markdownのコードブロックで指定した言語
  • data-theme:適用されているシンタックスハイライトテーマ(デフォルトはgithub-dark-dimmed

これらの属性や、生成されたHTMLの構造を把握した上で、CSSでスタイルをカスタマイズしてみましょう。

最低限のスタイル

Rehype Pretty CodeはCSSは提供しないため、スタイルの調整は自分で行う必要があります。レスポンシブ性や可読性を持たせるために、最低限当てるべきスタイルを見ていきましょう。

ハンズオン

横スクロール可能にする

現状、モバイルなどの横幅が狭い画面では、長いコードがはみ出して表示されてしまいます。

サンプルとして表示するコードブロック

```css
.shadow {
  /* offset-x | offset-y | blur-radius | color */
  box-shadow: 4px 6px 8px black;

  width: 200px;
  height: 200px;
  background-color: #d2e0fb;
}
```

次のCSSを追加して、横スクロール可能にしましょう。

狭い画面で横スクロール可能にするCSSの設定

pre {
  overflow-x: auto;
}

余白を設定する

コードの周囲にゆとりがない状態では、あまり見栄えが良いとはいえません。次の画像は先ほどのCSSのコードを描画したものです。コードブロックの黒背景がコードのぎりぎりのところを囲んでいます。

pre要素に次のようなpaddingを指定することで、コードの周囲に余白を持たせましょう。

インライン方向のpaddingは各行に持たせる

pre {
  padding-block: 0.75rem;
  padding-inline: 0;
}
pre [data-line] {
  padding-block: 0;
  /** 横スクロールした右端にも余白を適用するため、
   * インライン方向のpaddingはここで指定 */
  padding-inline: 1rem;
}

横スクロールを指定したpre要素のpadding-inline0にして、その孫要素のpre [data-line]のスタイルで上書きしているのは、横スクロールした際の右端に余白を適用するためです。

もしこのスタイルがなく、padding-inline: 1remなどでコードの周囲に余白をつけようとすると、画面を狭くした際、コードを横スクロールすると、右端の余白がない状態になってしまいます。

ブラウザの開発者ツールでpre要素を詳しく見てみると、pre要素の右端のpadding(緑色の部分)がはみ出したコードに重なってしまっていることがわかります。

長い行を描画するspan[data-line]要素は、pre要素からはみ出しています。

横スクロールすると、span[data-line]要素の右端が、コードブロックの右端と重なります。

横スクロールした際に、長い行の右端にも余白をつけるには、各行を描画するspan[data-line]要素にインライン方向のpaddingを設定することが必要です。

横スクロールした右端にも、余白が設定されるようになりました。これで、余白の指定は完了です。

その他のスタイル

その他のスタイルは、お好みで指定してください。以下に一例を示します。

例:コードのタイポグラフィと角丸の指定

/** タイポグラフィ */
code {
  font-family: 'Menlo', 'Lucida Console', 'Monaco', 'Consolas', monospace;
  font-size: 0.9rem;
  line-height: 1.5;
}

/** コードブロックの角丸 */
pre {
  border-radius: 5px;
}

コードブロックの見た目は次のようになります。

特に、font-familyにはお好みのmonospaceフォントを明示的に指定しておくと良いでしょう。

タイポグラフィに関するスタイルは、インラインコードでもコードブロックでも同様に適用されるよう、code要素に指定しています。

ここまでのまとめ

今回は、Rehype Pretty Codeの特長と、コードブロックの基本的なスタイリングのコツを解説しました。

今回はコードブロックを例にRehype Pretty Codeの使い方を解説しましたが、Rehype Pretty Codeを使うことで、インラインコードのシンタックスハイライト表示も強化することができます。

次回は、インラインコードのシンタックスハイライトに関する機能とスタイリング、配色テーマの変更、ライトモード・ダークモード設定に応じた配色テーマの切り替えといった、基本的な活用方法の続きを見ていきましょう。