Astro5.13 MDXのレンダリング結果をHTML文字列として取得する
いま別件でまたAstro製のブログを作ってて、諸事情により途中で記事ファイルをMarkdown -> MDXに変えたんだけど、そしたらもともとパラメータでHTML文字列を受け取るつもりだったコンポーネントが動かせなくなった。
AstroでMDXをレンダリングする時って render()
を使うけど、その戻り値はAstroのコンポーネントになるから、そのままじゃHTML文字列としては扱えない。それをHTML文字列に変換する方法を調べたのでメモ。
結論だけ知りたい人は最後の項だけ読んでください。
Markdownのレンダリング結果をHTMLとして取得する場合
まず最初に、MarkdownのコンテンツをHTMLとして取得して、レンダリングするコードはこんな感じ。
---
import { getEntry, render } from 'astro:content';
// ↓このコンテンツは *.md です
const id = '20251012-retrieve-the-mdx-rendering-result-as-an-html-string-in-astro-5.13';
const entry = await getEntry('blog', id);
if (!entry) {
throw new Error(`Entry not found: ${id}`);
}
---
<p>Published on: {entry.data.published.toDateString()}</p>
<Fragment set:html={entry.body.rendered?.html} />
AstroはFragment
という組み込みコンポーネントを持っていて、属性が無いなら <></>
で使えるけど、ここみたいに set:html
属性を指定する場合は <Fragment ... />
と書く。
MDXを普通にレンダリングする場合
次に、MDXをHTMLにせず普通にレンダリングするコードはこんな感じ。いや、上記ドキュメントのサンプルとほぼ同じだけど。
---
import { getEntry, render } from 'astro:content';
// ↓このコンテンツは *.mdx です
const id = '20251012-retrieve-the-mdx-rendering-result-as-an-html-string-in-astro-5.13';
const entry = await getEntry('blog', id);
if (!entry) {
throw new Error(`Entry not found: ${id}`);
}
const { Content, headings } = await render(entry);
---
<p>Published on: {entry.data.published.toDateString()}</p>
<Content />
こちらはMarkdownとは違って、 entry.body.rendered
は undefined
になってしまう。なお、このときコンソールに entry
を出力してみると deferredRender: true
というプロパティが追加されている。
上記の Content
はAstroのコンポーネントオブジェクト (型は AstroComponentFactory
) で、べつに他のAstroコンポーネントのpropsとしても使えるんだけど、今回はHTML文字列として取得したい。
MDXのレンダリング結果をHTMLとして取得する場合
MDXを render()
した戻りの Content
の内容をHTML文字列として取得したい場合は、Astro Container API (experimental)を使う。
Astro Container APIはexperimentalな機能なので将来のアップデートで変更される可能性があるけど、これを使うと、Astroコンポーネントを個別にレンダリングできるらしい。
---
import { getContainerRenderer as mdxContainerRenderer } from '@astrojs/mdx';
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import { loadRenderers } from 'astro:container';
import { getEntry, render } from 'astro:content';
const renderers = await loadRenderers([mdxContainerRenderer()]);
const container = await AstroContainer.create({ renderers });
// ↓このコンテンツは *.mdx です
const id = '20251012-retrieve-the-mdx-rendering-result-as-an-html-string-in-astro-5.13';
const entry = await getEntry('blog', id);
if (!entry) {
throw new Error(`Entry not found: ${id}`);
}
const { Content, headings } = await render(entry);
const html = await container.renderToString(Content);
---
<p>Published on: {entry.data.published.toDateString()}</p>
<Fragment set:html={html} />
この renderToString()
メソッドにAstroコンポーネントである Content
を渡すと、HTML文字列が返ってくる。ここではそれを Fragment
の set:html
属性に渡して、HTMLとしてレンダリングしている。
以上。なんか意外と、 *.md をただ *.mdx に変えただけじゃ動かないところがあって、面倒だなと思った。