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 の世界」が分かりやすかったので紹介します。
こんな感じの理解をしてます。
unist
というASTがあり、それの特化としてmdast
やhast
、nlcst
(なぜtast
にしなかった。。) がある。*-parse
でunist
に変換する。*-stringify
でunist
をそのフォーマットの文字列に変換する。
さらに
unist
からunist
に変換するtransform
を挟むことができ、ここにプラグインを刺すunist
同士の変換をremark-rehype
やrehype-remark
で行う
この一連の流れが unified
エコシステムで整理されています。
うーん。きれいですね。すばらしい。
remark-math / rehype-katexの導入
remark-mathとrehype-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$
は のようにレンダリングされます。
ブロックスタイルはこんな感じ。
$$
\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が にレンダリングしているので、おそらくその時だけCSSを追加するようにできると最適化されて良さそう。