AstroでMarkdownのレンダリングにカスタムコンポーネントを利用する

Published at
469 words
2min read

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 の場合は既存のエコシステムを使うで十分だと思うので、今回は試さなかった。