AstroでMarkdownのレンダリングにカスタムコンポーネントを利用する
AstroではMarkdownファイルにMDXやMarkdocと同様のAPIが利用できないため、Gatsybyなどの同様にremarkなどのpluginを利用する必要がある。
MDXのカスタムコンポーネント
Astroでは、MDX用にカスタムコンポーネントを利用できる機能が提供されている。
---
import Heading from "../Heading.astro";
---
<Content components={{ h1: Heading }} />
https://docs.astro.build/en/guides/markdown-content/#custom-components-with-imported-mdx
Markdown用には同様の機能がない
利用方法がほとんど同じだが、マークダウンには同様の機能がない。拡張子をmdxに変更すれば、そのまま利用することは出来るが、それが望ましいとは限らない。
https://github.com/withastro/roadmap/discussions/769
https://github.com/withastro/roadmap/discussions/423
公式ドキュメントにはMDXでは出来るとは書かれているが、Markdownでは出来ないとは書かれていないため、誤認したと思われる人による報告が見られる。
Remark pluginを利用する
GatsbyやNext.jsなどの他のフレームワークと同様に、remark pluginを利用して要素をカスタマイズすることは出来る。 一応Astro公式でも、カスタムコンポーネントを使う文脈ではないがremark pluginを利用する方法は紹介されている。
https://docs.astro.build/recipes/reading-time/
Astroのサンプルは、frontmatterを拡張するものだが、要素の変換も次のように行うことが出来る。
import { visit } from "unist-util-visit";
import { toString } from "mdast-util-to-string";
const remarkPluginSample = () => {
const transformer = (tree: any) => {
visit(tree, node => {
if (node.type !== "heading") return;
let { depth } = node;
if (depth !== 1) return;
let text = toString(node);
const html = `<h1 style="color: coral">${text}</h1>`;
node.type = "html";
node.children = undefined;
node.value = html;
});
};
return transformer;
};
export default defineConfig({
markdown: {
remarkPlugins: [remarkPluginSample],
},
});
余談:公式MDX Integrationの拡張を考える
@astrojs/mdx
のコードをざっくり見ると、内部APIのaddPageExtensionに.md
も追加すれば対応できるように思える。試してみて問題がなさそうであれば、PRを送ってみてもいいかもしれない。
個人的にはMarkdownの場合は既存のエコシステムを使うで十分だと思うので、今回は試さなかった。