Conao3 Note

AstroでKaTeXを使いたいぞという話


はじめに

Webで数式組版をしたい場合、MathJaxを使うというのが常識でしたが、前回のhugoブログを作った時点でKaTeXの方が早くて良いぞという話になっていました。 今回のAstroブログでもどうにか数式を表示したいということで、さくっと調べてみたのですが、あまり情勢は変わってないようだったので、KaTeXを導入することにします。

Remark / Rehype

AstroはMarkdownをHTMLにレンダリングする際、Remark/Rehypeを利用しているようです。(ref: MarkdownとMDXの設定)

Remark/Rehypeの関係は掴み辛いですが、「Introduction to unified」や「Remark で広げる Markdown の世界」が分かりやすかったので紹介します。

こんな感じの理解をしてます。

さらに

この一連の流れが unified エコシステムで整理されています。 うーん。きれいですね。すばらしい。

remark-math / rehype-katexの導入

remark-mathrehype-katexを導入します。

remark-math がマークダウン中の $C_L$ のような数式をmdast上で変換し、 rehype-katex がhast上でKaTeXを使うように変換します。

Astroでは書き下しませんが、READMEの例が分かりやすかったので引用します。

import {read} from 'to-vfile'
import {unified} from 'unified'
import remarkParse from 'remark-parse'
import remarkMath from 'remark-math'
import remarkRehype from 'remark-rehype'
import rehypeKatex from 'rehype-katex'
import rehypeStringify from 'rehype-stringify'

const file = await unified()
  .use(remarkParse)
  .use(remarkMath)
  .use(remarkRehype)
  .use(rehypeKatex)
  .use(rehypeStringify)
  .process(await read('example.md'))

console.log(String(file))

マークダウンの文字列をmdastに変換して、mdastでmathを変換して、hastに変換して、hastでkatexを変換して、htmlに変換しているのが分かります。

Astroでの設定

astro.config.mjsに追加

Astroから使えるようにするには astro.config.mjs に以下のように設定します。

 import { defineConfig } from 'astro/config';
 import mdx from '@astrojs/mdx';
 import sitemap from '@astrojs/sitemap';
+import remarkMath from 'remark-math';
+import rehypeKatex from 'rehype-katex';
 
 import react from "@astrojs/react";
 
 export default defineConfig({
   site: 'https://a.conao3.com',
   integrations: [mdx(), sitemap(), react()],
+  markdown: {
+    remarkPlugins: [remarkMath],
+    rehypePlugins: [rehypeKatex],
+  }
 });

CSSの追加

KaTeXのページからCSSのタグをコピーして良い感じのところに貼り付けます。 私はいろいろ面倒だったので、 src/component/BaseHeader.astro に貼り付けて全ページで読み込まれるようにしました。

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css" integrity="sha384-vKruj+a13U8yHIkAyGgK1J3ArTLzrFGBbBc0tDp4ad/EyewESeXE/Iv67Aj8gKZ0" crossorigin="anonymous">

動作確認

$C_L$CLC_L のようにレンダリングされます。

ブロックスタイルはこんな感じ。

$$
\frac{1}{\pi} = \frac{2\sqrt{2}}{99^2}
                \sum_{n=0}^\infty
                \frac{(4n)!}{(4^n n!)^4}
                \frac{1103 + 26390n}{99^{4n}}
$$
1π=22992n=0(4n)!(4nn!)41103+26390n994n\frac{1}{\pi} = \frac{2\sqrt{2}}{99^2} \sum_{n=0}^\infty \frac{(4n)!}{(4^n n!)^4} \frac{1103 + 26390n}{99^{4n}}

ちゃんと動いてそう。すばら。

まとめ

想像以上に簡単にできた。remark/rehypeというプロジェクトを知れたのも良かった。どんどん使っていきたい。

記事ごとレイアウトを指定すると良いという記事もあったが、多分それは記事のタイトルとか記事の抜粋で 別のページに出たときに壊れる気がするので、今回は全ページで読み込むようにした。

rehype-katexが KaTeX\KaTeX にレンダリングしているので、おそらくその時だけCSSを追加するようにできると最適化されて良さそう。

参考