astroのmarkdownの画像をpictureにする
markdown内の画像は最適化されていない
astroは割と画像回りの処理は気が利いていて,例えばPictureタグみたいな感じで画像を最適化してくれる.
しかしながら,マークダウン内の画像については,勝手にwebpに変換されるだけで特に設定なんかもみつからない.
せめてAvifとかformatを指定できないかなと調べていたら,同じことをastroの公式discordで質問している人がいて,それっぽい人が「remarkのプラグインを作ればいいよ」と言っていた.
正直それくらいできるようにしてくれんかと思ったが,せっかく作るなら最適化もしてしまおうということで,rehypeのプラグインを作ってみた.
rehypeのプラグインを作る
そもそもrehypeってなんだよという人はこの記事がわかりやすい.markdownをhtmlに変換するためのツールで,プラグインを作ると,htmlをいじったり色々と処理を追加できる.
今回作ったプラグインの流れは,
- imgタグを探す
- 画像をsharpでエンコードして,astroの出力ディレクトリに保存する
- imgタグをPictureタグに変換して,srcset等を設定する
という感じ.
1についてはunist-util-visit
を使って,rehypeのASTを探索している.ネットの海にいくらでもコードが転がっているので,それを参考にすればいい.すごく便利.
2.3も特に難しいことはない.sharpで画像をエンコードして,Pictureタグに変換するだけ.
astro-integrationにする
プラグインつくるだけで普通に使えるのだが,astroの出力先のフォルダとかキャッシュフォルダの指定とかastroの設定との兼ね合いがまだとれていない.astro-integrationにするとその辺の情報も取得できるので,そうすることにした.
公式のリファレンスがあるので,それを読むのもいいが,他人のコードを読んで改造するのが早い気がする.こういったライブラリに詳しくないのだが,慣れている人だったらすぐ理解できるのだろうか…
export default function mdImgToPic(): AstroIntegration {
return {
name: "astro-rehype-img2pic",
hooks: {
"astro:config:setup": async ({ command, config, updateConfig }) => {
if (command == "build") {
const pluginConfig = {
outDir: fileURLToPath(config.outDir),
cacheDir: fileURLToPath(config.cacheDir),
....
const rehypePlugin = configureMdImgToPicPlugin(pluginConfig);
updateConfig({
markdown: {
rehypePlugins: [rehypePlugin],
},
});
}
},
},
};
}
コードとしてはこんな感じ.
astro:config:setup
が初期化時に呼ばれるフックで,configureMdImgToPicPlugin
は設定を受け取って,rehypeのプラグインを返す高階関数で,それで出力された関数をupdateConfigでrehyePluginsに追加している.上手なやり方だと思う.(Github上にあったコードを参考にしました)
コード↓
Discussion