コンテンツにスキップ

AstroにおけるMarkdown

Markdownは、ブログ記事やドキュメントなど、テキストを多く含むコンテンツを書くためによく使われます。Astroには、タイトル、説明、タグなどのカスタムプロパティを定義するためのフロントマターYAML(またはTOML)も含められる、Markdownファイルの組み込みサポートが備わっています。

Astroでは、GitHub風のMarkdownでコンテンツを作成し、それを.astroコンポーネント内でレンダリングできます。これにより、コンテンツ向けに設計された使い慣れた記述形式と、Astroのコンポーネント構文・アーキテクチャの柔軟性を組み合わせることができます。

ローカルのMarkdownファイルは、src/ディレクトリ内のどこにでも配置できます。src/pages/内に配置されたMarkdownファイルは、サイト上にMarkdownページを自動的に生成します。

Markdownのコンテンツとフロントマタープロパティは、ローカルファイルのインポートを通じて、あるいはコンテンツコレクションのヘルパー関数で取得したデータからクエリしてレンダリングする際に、コンポーネントから利用できます。

ファイルインポートとコンテンツコレクションのクエリ

Section titled “ファイルインポートとコンテンツコレクションのクエリ”

ローカルのMarkdownは、単一のファイルであればimport文で、複数のファイルを一度にクエリしたい場合はViteのimport.meta.glob() (EN)を使って、.astroコンポーネントにインポートできます。Markdownファイルからエクスポートされるデータは、このようにして.astroコンポーネント内で利用できます。

関連するMarkdownファイルのグループがある場合は、コレクションとして定義する (EN)ことを検討してください。コレクションには、ファイルシステム上の任意の場所やリモートにMarkdownファイルを保存できるなど、いくつかの利点があります。

コレクションでは、ファイルインポートではなく、Markdownコンテンツのクエリとレンダリングに特化した最適化されたAPIを使用します。コレクションは、ブログ記事や製品情報など、同じ構造を共有するデータセットを対象としています。スキーマでその構造を定義すれば、バリデーション、型安全性、エディタ上のインテリセンスも得られます。

ファイルインポートの代わりにコンテンツコレクションを使うべきタイミング (EN)について詳しく見る。

Markdownファイルをインポートまたはクエリしたあと、フロントマターのデータや本文を含む動的なHTMLテンプレートを.astroコンポーネント内で記述できます。

src/pages/posts/great-post.md
---
title: '史上もっとも素晴らしい投稿'
author: 'Ben'
---
これが私の_素晴らしい_投稿です!
src/pages/my-posts.astro
---
import * as greatPost from "./posts/great-post.md";
const compiled = await greatPost.compiledContent();
const posts = Object.values(import.meta.glob("./posts/*.md", { eager: true }));
---
<p>{greatPost.frontmatter.title}</p>
<p>執筆者: {greatPost.frontmatter.author}</p>
<Fragment set:html={compiled} />
<p>過去の投稿:</p>
<ul>
{
posts.map((post: any) => (
<li>
<a href={post.url}>{post.frontmatter.title}</a>
</li>
))
}
</ul>

コンテンツコレクションのクエリから取得したMarkdown

Section titled “コンテンツコレクションのクエリから取得したMarkdown”

getCollection()やgetEntry()といったヘルパー関数でコレクションからデータを取得する場合、Markdownのフロントマタープロパティはdataオブジェクト経由で利用できます(例: post.data.title)。さらに、bodyにはコンパイルされていない生の本文コンテンツが文字列として含まれます。

render() (EN)関数は、Markdownの本文、生成された見出しのリスト、およびMarkdownプロセッサプラグインが適用されたあとの変更済みフロントマターオブジェクトを返します。

importまたはimport.meta.glob()を使ってMarkdownをインポートした場合、.astroコンポーネント内で以下のエクスポートされたプロパティが利用できます。

  • file - ファイルの絶対パス(例: /home/user/projects/.../file.md)。
  • url - ページのURL(例: /en/guides/markdown-content)。
  • frontmatter - ファイルのYAML(またはTOML)フロントマターで指定されたデータ。
  • <Content /> - ファイルの完全なレンダリング済みコンテンツを返すコンポーネント。
  • rawContent() - 生のMarkdownドキュメントを文字列として返す関数。
  • compiledContent() - MarkdownドキュメントをHTML文字列にコンパイルして返す非同期関数。
  • getHeadings() - ファイル内のすべての見出し(<h1>から<h6>)の配列を、{ depth: number; slug: string; text: string }[]型で返す非同期関数。各見出しのslugは、その見出しに対して生成されるIDに対応しており、アンカーリンクに利用できます。

たとえばMarkdownのブログ記事では、次のようなAstro.propsオブジェクトが渡されます。

Astro.props = {
file: "/home/user/projects/.../file.md",
url: "/en/guides/markdown-content/",
frontmatter: {
/** Frontmatter from a blog post */
title: "Astro 0.18 Release",
date: "Tuesday, July 27 2021",
author: "Matthew Phillips",
description: "Astro 0.18 is our biggest release since Astro launch.",
},
getHeadings: () => [
{"depth": 1, "text": "Astro 0.18 Release", "slug": "astro-018-release"},
{"depth": 2, "text": "Responsive partial hydration", "slug": "responsive-partial-hydration"}
/* ... */
],
rawContent: () => "# Astro 0.18 Release\nA little over a month ago, the first public beta [...]",
compiledContent: () => "<h1>Astro 0.18 Release</h1>\n<p>A little over a month ago, the first public beta [...]</p>",
}

<Content />コンポーネントは、MarkdownファイルからContentをインポートすることで利用できます。このコンポーネントは、ファイルの本文全体をHTMLにレンダリングして返します。Contentは好みの名前にリネームすることもできます。

同様に、<Content />コンポーネントをレンダリングすることで、Markdownコレクションエントリの本文をHTMLとしてレンダリング (EN)できます。

src/pages/content.astro
---
// import文
import {Content as PromoBanner} from '../components/promoBanner.md';
// コレクションのクエリ
import { getEntry, render } from 'astro:content';
const product = await getEntry('products', 'shirt');
const { Content } = await render(product);
---
<h2>本日のキャンペーン</h2>
<PromoBanner />
<p>セール終了日: {product.data.saleEndDate.toDateString()}</p>
<Content />

Markdownで見出しを書くと、ページ内の特定のセクションに直接リンクできるアンカーリンクが自動的に付与されます。

src/pages/page-1.md
---
title: コンテンツのページ
---
## はじめに
Markdownを書く際、同じページ内の[結論](#結論)に内部リンクできます。
## 結論
ブラウザで`https://example.com/page-1/#はじめに`を開けば、「はじめに」へ直接遷移できます。

Astroは、github-sluggerに基づいて見出しのidを生成します。その他の例はgithub-sluggerのドキュメントを参照してください。

Astroは、MarkdownおよびMDXファイル内のすべての見出し要素(<h1>から<h6>)にid属性を注入します。このデータは、インポートしたファイルのMarkdownエクスポートプロパティとして提供されるgetHeadings()ユーティリティ、またはコンテンツコレクションのクエリから返されたMarkdownを使う際のrender()関数から取得できます。

これらの見出しIDは、id属性を注入するMarkdownプロセッサプラグイン(例: rehype-slug)でカスタマイズできます。これにより、Astroのデフォルトの代わりにカスタムIDが、HTML出力とgetHeadings()が返す項目に反映されます。

Astroは、カスタムプラグインの実行後にid属性を注入するため、プラグインによってセットされたIDは保持されます。カスタムプラグインがAstroによって注入されたIDにアクセスする必要がある場合は、Astroの見出しIDプラグインをインポートし、それに依存するプラグインより前に配置してください。

astro.config.mjs
import { defineConfig } from 'astro/config';
import { satteri, satteriHeadingIdsPlugin } from '@astrojs/markdown-satteri';
import { otherPluginThatReliesOnHeadingIDs } from 'some/plugin/source';
export default defineConfig({
markdown: {
processor: satteri({
hastPlugins: [
satteriHeadingIdsPlugin(),
otherPluginThatReliesOnHeadingIDs,
],
}),
},
});

追加: astro@6.4.0

MarkdownプロセッサはMarkdown構文を解析しHTMLに変換します。Markdownの機能を拡張するために標準機能を提供したり、プラグインを追加したりすることができます。

Astroは2つの公式プロセッサ(SätteriとUnified)を提供します。プロジェクト全体にプロセッサを設定したり、MarkdownやMDXに対して他のプロセッサを選択したりすることができます。

Astro v7以降、SätteriがデフォルトのMarkdownプロセッサです。ユーザーのプロジェクトの必要性に応じて、インストールや設定を一切行うことなくMarkdownやMDXファイルをレンダリングするために利用できます。

各プロセッサは同一の標準機能を提供しますが、アーキテクチャや利点にわずかな違いがあります。

SätteriはAstro v7以降デフォルトのMarkdownプロセッサです。以下のケースで利用します。

  • 高速なRustベースのMarkdownおよびMDXコンパイラの利点を得たい場合。
  • プロジェクトでプラグインが必要ない場合、あるいは独自のプラグインを開発することに抵抗がない場合。

Unifiedは以前のバージョンのAstroで使われていたプロセッサです。以下のケースで利用します。

  • remarkやrehypeプラグインなどの大きなエコシステムのアドバンテージを取りたい場合、もしくはMDXファイルのrecmaプラグインが必要な場合。
  • 既存のUnifiedプラグインをSätteriに移行する準備が整っていない場合。

Markdownプロセッサのセットアップ

Section titled “Markdownプロセッサのセットアップ”

AstroはMarkdownの設定オプション (EN)を提供しており、シンタックスハイライトやMarkdownプロセッサを制御できます。さらに、各Markdownプロセッサは設定可能な機能を提供し、プラグインを追加してMarkdownレンダリングをカスタマイズできます。

Sätteriはデフォルトでインストールや設定無しで動作します。設定したりプラグインを追加したりする場合には明示的にインストールしてください。

  1. @astrojs/markdown-satteriパッケージをインストールします。

    ターミナルウィンドウ
    npm install @astrojs/markdown-satteri
  2. Astro設定ファイル内で、@astrojs/markdown-satteriからsatteriをインポートしてmarkdown.processor (EN)オプションに渡してください。

    astro.config.mjs
    import { defineConfig } from "astro/config";
    import { satteri } from "@astrojs/markdown-satteri";
    export default defineConfig({
    markdown: {
    processor: satteri(),
    },
    });

2つの公式Markdownプラグインはデフォルトで同じ機能を提供します。これには、GitHub風のMarkdownやスマート句読点のサポートが含まれます。これらの機能は無効化したり、カスタマイズしたり、プラグインを追加して新しい機能を導入することもできます。

AstroのMarkdownプロセッサはデフォルトでGitHub風のMarkdown(GFM)をサポートしています。これは、オリジナルのMarkdown仕様のスーパーセットであり、テーブル、取り消し線、タスクリスト、脚注などの機能を追加したものです。

GFMを無効化したい場合は、プロセッサのオプションでgfmをfalseに設定してください。

astro.config.mjs
import { defineConfig } from "astro/config";
import { satteri } from "@astrojs/markdown-satteri";
export default defineConfig({
markdown: {
processor: satteri({
features: { gfm: false },
}),
},
});

脚注を設定するには、Sätteriの場合はgfm.footnotesに、Unifiedの場合はremarkRehypeに設定オブジェクトを渡します。

astro.config.mjs
import { defineConfig } from "astro/config";
import { satteri } from "@astrojs/markdown-satteri";
export default defineConfig({
markdown: {
processor: satteri({
features: {
gfm: {
// デフォルトの脚注の設定
footnotes: {
backContent: "↩",
backLabel: "Back to reference {reference}",
label: "Footnotes",
},
},
},
}),
},
});

AstroのMarkdownプロセッサはデフォルトでSmartypantsに基づいたスマート句読点をサポートしています。この機能は自動的に、ストレート引用符をカール引用符に、ダブルハイフンをEMダッシュに、三点リーダーを省略記号に変換します。

自動変換を利用したくない場合は、プロセッサのオプションでスマート句読点を無効化できます。

astro.config.mjs
import { defineConfig } from "astro/config";
import { satteri } from "@astrojs/markdown-satteri";
export default defineConfig({
markdown: {
processor: satteri({
features: { smartPunctuation: false },
}),
},
});

タイポグラフィさらに制御したい場合は、代わりにプロセッサのオプションで設定オブジェクトを指定できます。

astro.config.mjs
import { defineConfig } from "astro/config";
import { satteri } from "@astrojs/markdown-satteri";
export default defineConfig({
markdown: {
processor: satteri({
features: {
smartPunctuation: {
quotes: true,
dashes: false,
ellipses: false,
},
},
}),
},
});

Markdownプロセッサプラグインを使うと、Markdownに新しい機能を追加できます。例えば、目次の自動生成、アクセシブルな絵文字ラベルの適用、Markdownのスタイリング (EN)などが可能です。これらのプラグインは、処理パイプラインの個別の段階で構文ツリーを変更できます。

2種類のプラグインがサポートされています。

  • mdastプラグイン HTMLに変換前のMarkdown構文ツリー(mdast)上で操作します。Unifiedではこれらをremarkプラグインと呼びます。
  • hastプラグイン MarkdownからHTMLに変換後のHTML構文ツリー(hast)上で操作します。Unifiedではこれらをrehypeプラグインと呼びます。

mdastやhastプラグインの挙動を変更する場合、プラグイン関数にオプションオブジェクトを引数として渡すことができます。

以下の例は、Markdownファイルにsatteri-imgattrとsatteri-calloutsを適用しています。

astro.config.mjs
import { defineConfig } from "astro/config";
import { satteri } from "@astrojs/markdown-satteri";
import imgAttr from "satteri-imgattr";
import satteriCallouts from "satteri-callouts";
export default defineConfig({
markdown: {
processor: satteri({
mdastPlugins: [
imgAttr({
defaults: { loading: "lazy", decoding: "async" },
}),
],
hastPlugins: [satteriCallouts()],
}),
},
});

プログラムによるフロントマターの変更

Section titled “プログラムによるフロントマターの変更”

プロセッサプラグインを使用することで、すべてのMarkdownおよびMDXファイルにフロントマタープロパティを追加できます。

  1. data.astro.frontmatterオブジェクトにカスタムプロパティを追加します。

    data.astro.frontmatterはMarkdownやMDXドキュメントのフロントマターのすべてのプロパティを含みます。これにより、既存のフロントマタープロパティを変更したり、既存のフロントマターから新しいプロパティを計算したりできます。

    example-mdast-plugin.ts
    import { defineMdastPlugin } from "satteri";
    export const exampleMdastPlugin = defineMdastPlugin({
    name: "example-mdast-plugin",
    text(node, ctx) {
    if (ctx.data.astro !== undefined) {
    ctx.data.astro.frontmatter.newProperty = "New property";
    // `title`は必須のフロントマタープロパティであると仮定します
    ctx.data.astro.frontmatter.computedProperty = `${ctx.data.astro.frontmatter.title} | My Site Name`;
    }
    },
    });
  2. このプラグインをmarkdown設定に追加します。

    astro.config.mjs
    import { defineConfig } from "astro/config";
    import { satteri } from "@astrojs/markdown-satteri";
    import { exampleMdastPlugin } from "./example-mdast-plugin";
    export default defineConfig({
    markdown: {
    processor: satteri({ mdastPlugins: [exampleMdastPlugin()] }),
    },
    });

これで、すべてのMarkdownやMDXファイルのフロントマターにnewPropertyとcomputedPropertyが含まれており、インポートされたMarkdownファイル、レイアウト使用時のAstro.props.frontmatterプロパティ、またはコンテンツレンダリング時のremarkPluginFrontmatter (EN)を介して利用できるようになります。

関連レシピ: Add reading time (EN)

Astroは、/src/pages/ディレクトリ内のサポートされているすべてのファイルをページとして扱い、.mdやその他のMarkdownファイルタイプも対象に含まれます。

このディレクトリやそのサブディレクトリにファイルを配置すると、ファイルのパス名を使ったページルートが自動的に構築され、HTMLにレンダリングされたMarkdownコンテンツが表示されます。非ASCIIコンテンツを書きやすくするため、Astroはページに<meta charset="utf-8">タグを自動的に追加します。

src/pages/page-1.md
---
title: Hello, World
---
# こんにちは!
このMarkdownファイルは、`your-domain.com/page-1/`にページを作成します。
スタイルはほとんど当たっていないかもしれませんが、Markdownは以下のような記法をサポートしています。
- **太字**と_イタリック_
- リスト
- [リンク](https://astro.build)
- <p>HTML要素</p>
- などなど!

フロントマターのlayoutプロパティ

Section titled “フロントマターのlayoutプロパティ”

個別のMarkdownページは機能が限られているため、Astroはそれを補う特別なフロントマタープロパティとしてlayoutを提供しています。これはAstroのMarkdownレイアウトコンポーネントへの相対パスです。layoutは、コンテンツコレクション (EN)を使ってMarkdownコンテンツをクエリ・レンダリングする際の特別なプロパティではなく、本来の用途以外でのサポートは保証されません。

Markdownファイルがsrc/pages/内にある場合は、レイアウトコンポーネントを作成し、このlayoutプロパティに指定することで、Markdownコンテンツの周りにページのシェルを与えられます。

src/pages/posts/post-1.md
---
layout: ../../layouts/BlogPostLayout.astro
title: Astroの概要
author: Himanshu
description: Astroが素晴らしい理由を見つけよう!
---
これはMarkdownで書かれた投稿です。

このレイアウトコンポーネントは通常のAstroコンポーネントですが、AstroテンプレートのAstro.propsを通じて特定のプロパティが自動的に利用可能になります。たとえば、MarkdownファイルのフロントマタープロパティにはAstro.props.frontmatterからアクセスできます。

src/layouts/BlogPostLayout.astro
---
const {frontmatter} = Astro.props;
---
<html>
<head>
<!-- ... -->
<meta charset="utf-8"> // デフォルトでは追加されなくなる
</head>
<!-- ... -->
<h1>{frontmatter.title}</h1>
<h2>投稿者: {frontmatter.author}</h2>
<p>{frontmatter.description}</p>
<slot /> <!-- ここにMarkdownコンテンツが挿入される -->
<!-- ... -->
</html>

フロントマターのlayoutプロパティを使用する場合、Astroは<meta charset="utf-8">タグを自動的に追加しなくなるため、レイアウト内に自分で含める必要があります。また、レイアウトコンポーネント内でMarkdownにスタイルを当てる (EN)こともできます。

Markdownレイアウトについて詳しく学ぶ。

Astro内部のMarkdownプロセッサは、リモートのMarkdownを処理するためには利用できません。

コンテンツコレクション (EN)で使うためにリモートのMarkdownを取得するには、renderMarkdown()関数 (EN)にアクセスできるカスタムローダーを作成 (EN)します。

リモートのMarkdownを直接取得してHTMLにレンダリングするには、NPMから自分でMarkdownパーサーをインストールして設定する必要があります。この場合、Astro組み込みのMarkdown設定は引き継がれません。

プロジェクトに実装する前にこうした制約を理解し、代わりにコンテンツコレクションのローダーを使ってリモートのMarkdownを取得できないか検討してください。

src/pages/remote-example.astro
---
// 例: リモートAPIからMarkdownを取得し、
// 実行時にHTMLへレンダリングする。
// "marked"(https://github.com/markedjs/marked)を使用
import { marked } from 'marked';
const response = await fetch('https://raw.githubusercontent.com/wiki/adam-p/markdown-here/Markdown-Cheatsheet.md');
const markdown = await response.text();
const content = marked.parse(markdown);
---
<article set:html={content} />
貢献する コミュニティ スポンサー