AstroでURL末尾に.mdを付けた時にMarkdownを表示させる
Created At: 2025/05/03 23:59
Updated At: 2025/05/04 18:19
- モノヅクリ
- astro
Twitterで見かけたやつを本ブログに実装しました。
関係ない (ちょっとある) けど、Qiitaが記事のURL末尾に .md をつけると Markdown を返してくれたり、GitHub の Pull Request の URL 末尾に .diff をつけると diff を返してくれるのめっちゃ好き
— Yuya Takeyama (@yuya_takeyama) May 2, 2025
なるほど確かに、今後LLMに読んでもらうことを考えると、プレーンテキストを返すのは良いアイデアですね(QiitaのこれはAIとかよりも遥か昔からあった上に大抵のAIサービスはURLを与えると勝手にhtml-to-textしてくれると思いますが)。LLMに限らず普通にコピペするときとかも便利そうです。
ということで本ブログでも実装してみました。
実装方法
本ブログのコンテンツはMarkdownで管理しており、ビルド時に生Markdownを取得可能なため、Astroの静的ファイルエンドポイントとして実装しました。
import { join } from "node:path";import type { APIRoute } from "astro";import { stringify } from "yaml";import type { AstroPostEntry } from "../../content.config";import { getPosts } from "../../utils/getPost";
export async function getStaticPaths() { const blogEntries = await getPosts(); return blogEntries.map((entry) => ({ params: { id: entry.id }, props: { entry }, }));}
export const GET: APIRoute<{ entry: AstroPostEntry }> = async ({ props, url,}) => { const md = props.entry.body ?? "";
// ローカル画像参照箇所をフルパスに変換 const localImagePaths = (props.entry.rendered?.metadata?.localImagePaths as string[] | undefined) ?? []; const localPathsMap = new Map( localImagePaths.map((path) => { const localFullPath = join(props.entry.filePath ?? "", path).replace( "src/public", "", ); const remoteUrl = new URL(localFullPath, url); return [path, remoteUrl.toString()]; }), ); const replaced = md.replace( /!\[([^\]]*)\]\(([^)]+)\)/g, (match, alt, path) => { const replacedPath = localPathsMap.get(path); if (replacedPath) { return ``; } return match; }, );
// frontmatterをyamlに変換して先頭に結合 const frontmatter = stringify(props.entry.rendered?.metadata?.frontmatter); const joined = `---\n${frontmatter}---\n${replaced}`;
return new Response(joined, { headers: { "Content-Type": "text/markdown; charset=utf-8", "Access-Control-Allow-Origin": "*", }, });};
やっていることは以下の通りです。
getStaticPaths
で全てのブログ記事を取得- 生Markdownを取得
- Markdown内のローカル画像参照をフルパスに変換
- FrontmatterをYAMLに変換してMarkdownの先頭に結合
text/markdown
としてレスポンスを返す- 参考元のQiitaでは
text/x-markdown
を返しているようですが、2016年3月にtext/markdown
がRFC 7763として登録されています。
- 参考元のQiitaでは
案外スッと実装できました。これでURL末尾に.md
をつけるとMarkdownが返ってきます。
ローカル画像パスの変換処理周り見落としがありそうなのでちゃんとテストしないといけなさそうですが一旦動いているのでヨシ!