MarkdownとMDX
Markdownは、ブログ投稿やドキュメントのようなテキストを多用するコンテンツのオーサリングによく使います。Astroは標準的なMarkdownファイルをビルトインでサポートしています。
@astrojs/mdxインテグレーション (EN)をインストールすると、MDX(.mdx
)ファイルにも対応し、MarkdownコンテンツでのJavaScript式やコンポーネントのサポートなどの追加機能を提供します。
Markdownコンテンツを書くには、どちらか一方、または両方のタイプのファイルを使用します。
MarkdownページとMDXページ
Section titled MarkdownページとMDXページファイルベースルーティング
Section titled ファイルベースルーティングAstroは、/src/pages/
ディレクトリ内の.md
(または対応する別の拡張子)または.mdx
ファイルをページとして扱います。
このディレクトリ、またはサブディレクトリにファイルを置くと、ファイルのパス名を使って自動的にページルートを構築します。
---
title: Hello, World
---
# こんにちは!
このMarkdownファイルは `your-domain.com/page-1/`にページを作成します。
スタイリングとしてはおそらく不十分ですが、Markdownは以下をサポートしています。
- **太字** と _イタリック_
- リスト
- [リンク](https://astro.build)
- などなど
📚 Astroのファイルベースルーティングや、動的ルーティングを作成するオプションについてもっと読む。
下書きページ
Section titled 下書きページdraft: true
はオプションのfront-matterの値で、個々のMarkdownまたはMDXページや投稿を「非公開」としてマークできます。デフォルトでは、マークされたページは次の動作になります。
- サイトのビルド対象から外す(ページはビルドされない)
Astro.glob()
(EN)によって返される (投稿の一覧で表示されます)
---
layout: ../../layouts/BaseLayout.astro
title: ブログ記事
draft: true
---
これは、作成中のブログ記事です。
この記事のためにページは作成されません。
この記事をビルドして公開するには
- front-matterを`draft: false`に更新する。
- または、`draft`プロパティ全体を削除してください。
しかし、このページは `Astro.glob()` にマッチするすべてのリクエストで返されます。
下書きの投稿を、投稿アーカイブや最新投稿のリストに含めないようにするには、Astro.glob()
が返す結果をフィルタリングしてください。
const posts = await Astro.glob('../pages/post/*.md');
const nonDraftPosts = posts.filter((post) => !post.frontmatter.draft);
下書きページのビルドを有効にする
Section titled 下書きページのビルドを有効にするデフォルトで下書きページもビルドするには、markdown
またはmdx
インテグレーションにdrafts: true
を追加してastro.config.mjs
を更新します。
export default defineConfig({
markdown: {
drafts: true,
},
integrations: [mdx({
drafts: true,
})],
});
Markdownの機能
Section titled Markdownの機能Astroは、MarkdownとMDXファイルを使用する際に利用できる、追加のビルトインMarkdown機能を提供します。
Front-matter layout
Section titled Front-matter layoutAstroは、MarkdownおよびMDXページに、Astroレイアウトコンポーネントへの相対パス(またはエイリアス)を指定できる特別なfront-matter用のlayout
プロパティを提供します。
---
layout: ../../layouts/BlogPostLayout.astro
title: Astroの概要
author: Himanshu
description: Astroの凄さを知ってください!
---
これはMarkdownで書かれた記事です。
front-matterプロパティは、Astro.props
を使ってレイアウトで利用できます。
---
const {frontmatter} = Astro.props;
---
<html>
<!-- ... -->
<h1>{frontmatter.title}</h1>
<h2>投稿者: {frontmatter.author}</h2>
<p>{frontmatter.description}<p>
<slot /> <!-- Markdownコンテンツはここに挿入されます -->
<!-- ... -->
</html>
📚 Markdownのレイアウトの詳細を見る。
見出しID
Section titled 見出しIDMarkdownとMDXで見出しを使用すると、自動的にアンカーリンクが作成され、ページ内の特定のセクションに直接リンクできます。
---
title: コンテンツページ
---
## イントロダクション
Markdownで書くと、同じページの[結論](#結論)に内部リンクできます。
## 結論
URL`https://my-domain.com/page-1/#イントロダクション`を使って、ページ上のイントロダクションに直接移動できます。
特殊文字のエスケープ
Section titled 特殊文字のエスケープ特定の文字は、MarkdownおよびMDXにおいて、特別な意味を持っています。それらを表示したい場合、異なる構文を使用する必要があるかもしれません。表示するには、これらの文字の代わりにHTMLエンティティを使用します。
たとえば、<
がHTML要素の先頭と解釈されないようにするには、<
と記述します。また、MDXで{
がJavaScriptの式の先頭と解釈されないようにするには、{
と記述します。
MDXのみで使える機能
Section titled MDXのみで使える機能AstroのMDXインテグレーション (EN)を追加すると、JSX変数、式、コンポーネントによってMarkdownオーサリングを強化できます。
また、MDXにおけるMarkdownスタイルのfront-matterのサポートなど、標準的なMDXにさらに機能を追加しています。これにより、front-matter layout
プロパティや下書きページの設定など、Astroの組み込みMarkdown機能のほとんどを使用できます。
.mdx
ファイルは、AstroのHTMLライクな構文ではなく、MDX構文で記述する必要があります。
MDXでエクスポートされた変数を使用する
Section titled MDXでエクスポートされた変数を使用するMDXは、export
文を使用してMDXコンテンツに変数を追加することをサポートします。これらの変数は、テンプレート自体でも、ファイルをどこかにインポートするときに名前付きプロパティとしてでもアクセスできます。
たとえば、MDXページやコンポーネントからtitle
フィールドをエクスポートして、{JSX expressions}
で見出しとして使用できます。
export const title = 'はじめてのMDXの投稿'
# {title}
MDXでfront-matter変数を使用する
Section titled MDXでfront-matter変数を使用するAstro MDXインテグレーションには、MDXでfront-matterを使用するためのサポートがデフォルトで含まれています。Markdownファイルと同じようにfrontmatterプロパティを追加すると、これらの変数はテンプレートやlayout
コンポーネント内において、あるいはどこかにファイルをインポートするときに名前付きプロパティとして使用する際にアクセスできます。
---
layout: '../../layouts/BlogPostLayout.astro'
title: 'はじめてのMDXの投稿'
---
# {frontmatter.title}
MDXでコンポーネントを使用する
Section titled MDXでコンポーネントを使用するMDXインテグレーションをインストールすると、AstroコンポーネントとUIフレームワークコンポーネントの両方をMDX(.mdx
)ファイルにインポートして、他のAstroコンポーネントと同じように使用できるようになります。
必要であれば、UIフレームワークのコンポーネントにclient:directive
をつけ忘れないよう注意してください。
MDX docsでimportとexport文の他の使用例を確認してください。
---
layout: ../layouts/BaseLayout.astro
title: About me
---
import Button from '../components/Button.astro';
import ReactCounter from '../components/ReactCounter.jsx';
私は**火星**に住んでいますが、気軽に<Button title="お問い合わせ" />までご連絡ください。
以下は、MDXで動作するカウンターコンポーネントです。
<ReactCounter client:load />
カスタムコンポーネントをHTML要素に割り当てる
Section titled カスタムコンポーネントをHTML要素に割り当てるMDXを使用すると、標準のHTML要素の代わりに、Markdown構文をカスタムコンポーネントにマッピングできます。これにより、標準的なMarkdown構文で記述しながら、選択された要素に特別なコンポーネントスタイルを適用できます。
カスタムコンポーネントを.mdx
ファイルにインポートし、標準のHTML要素をカスタムコンポーネントにマップするcomponents
オブジェクトをエクスポートします。
import Blockquote from '../components/Blockquote.astro';
export const components = {blockquote: Blockquote}
> この引用文はカスタムBlockquoteになります。
---
const props = Astro.props;
---
<blockquote {...props} class="bg-blue-50 p-4">
<span class="text-4xl text-blue-600 mb-2">“</span>
<slot /> <!-- 子コンテンツのために `<slot/>` を必ず追加してください! -->
</blockquote>
カスタムコンポーネントとして上書き可能なHTML要素の全リストは、MDXのウェブサイトをご覧ください。
Markdownのインポート
Section titled MarkdownのインポートMarkdownファイルやMDXファイルをAstroファイルに直接インポートできます。これにより、そのMarkdownコンテンツや、AstroのJSXライクな式で使用できるfront-matterの値などのプロパティにアクセスできます。
import
文で特定の1ページを、Astro.glob()
で複数のページをインポートできます。
---
// 1つのファイルのインポート
import * as myPost from '../pages/post/my-post.md';
// Astro.globによる複数ファイルのインポート
const posts = await Astro.glob('../pages/post/*.md');
---
AstroコンポーネントでMarkdownやMDXファイルをインポートすると、そのエクスポートされたプロパティを含むオブジェクトが取得されます。
---
title: '今まで書いた中で最高の投稿'
author: 'Ben'
---
**素晴らしい**投稿をご紹介します。
---
import * as greatPost from '../pages/post/great-post.md';
const posts = await Astro.glob('../pages/post/*.md');
---
<p>{greatPost.frontmatter.title}</p>
<p>執筆者: {greatPost.frontmatter.author}</p>
<p>投稿アーカイブ:</p>
<ul>
{posts.map(post => <li><a href={post.url}>{post.frontmatter.title}</a></li>)}
</ul>
MDXファイルでは、front-matterとexport
文の両方からプロパティにアクセスできます。
---
title: '今まで書いた中で最高の投稿'
author: 'Ben'
---
export const description = '快適に過ごそう! これは素晴らしい読み物になりそうです。'
私の**素晴らしい**投稿をご紹介します。
---
import * as greatPost from '../pages/post/mdx-post.mdx';
---
<p>{greatPost.frontmatter.title}</p>
<p>執筆者: {greatPost.frontmatter.author}</p>
<p>{greatPost.description}</p>
オプションとして、TypeScriptのジェネリックを使用してfrontmatter
変数の型を指定できます。
---
interface Frontmatter {
title: string;
description?: string;
}
const posts = await Astro.glob<Frontmatter>('../pages/post/*.md');
---
<ul>
{posts.map(post => <li>{post.frontmatter.title}</li>)}
<!-- post.frontmatter.title は `string`! -->
</ul>
エクスポートしたプロパティ
Section titled エクスポートしたプロパティ.astro
コンポーネントでimport
文またはAstro.glob()
を使用した場合、以下のプロパティが使用できます。
file
- ファイルの絶対パス(例:/home/user/projects/.../file.md
)。url
- もしページなら、そのページのURL (例:/en/guides/markdown-content
)。frontmatter
- ファイルのYAML front-matterで指定された全データを含みます。getHeadings
- ファイル内のすべての見出し(すなわちh1 -> h6
要素)の配列を返す非同期関数です。各見出しのslug
は、与えられた見出しに対して生成されたIDに対応し、アンカーリンクに使用できます。このリストは次の型に従います。{ depth: number; slug: string; text: string }[]
。Content
- ファイルのレンダリングされた完全なコンテンツを返すコンポーネントです。- (Markdownのみ)
rawContent()
- 生のMarkdownドキュメントを文字列として返す関数です。 - (Markdownのみ)
compiledContent()
- HTML文字列にコンパイルされたMarkdownドキュメントを返す関数です。これはfront-matterで設定されたレイアウトを含まないことに注意してください。Markdownドキュメント自身のみがHTMLとして返されます。 - (MDXのみ) - MDXファイルは、
export
文を使用してデータをエクスポートすることもできます。
Content
コンポーネント
Section titled Content コンポーネントContent
をインポートすると、MarkdownまたはMDXファイルを完全にレンダリングしたコンテンツを返すコンポーネントを使用できます。
---
import {Content as PromoBanner} from '../components/promoBanner.md';
---
<h2>本日のプロモーション</h2>
<PromoBanner />
例:動的ページルーティング
Section titled 例:動的ページルーティングMarkdown/MDXファイルをsrc/pages/
ディレクトリに置いてページルートを作成する代わりに、ページを動的に生成できます。
Markdownコンテンツにアクセスするには、Astroページのprops
に<Content/>
コンポーネントを渡します。そして、Astro.props
からコンポーネントを取得し、ページテンプレートにレンダリングできます。
---
export async function getStaticPaths() {
const posts = await Astro.glob('../posts/**/*.md')
return posts.map(post => ({
params: {
slug: post.frontmatter.slug
},
props: {
post
},
}))
}
const { Content } = Astro.props.post
---
<article>
<Content/>
</article>
エクスポート(MDXのみ)
Section titled エクスポート(MDXのみ)MDXファイルでは、export
文を使用してデータをエクスポートできます。
たとえば、MDXページやコンポーネントからtitle
フィールドをエクスポートできます。
export const title = 'はじめてのMDXの投稿'
このtitle
はimport
やAstro.glob()
(EN)文からアクセスできます。
---
const posts = await Astro.glob('./*.mdx');
---
{posts.map(post => <p>{post.title}</p>)}
インポートしたMDXを使ったカスタムコンポーネント
Section titled インポートしたMDXを使ったカスタムコンポーネントインポートしたMDXコンテンツをレンダリングする際、components
プロパティでカスタムコンポーネントを渡せます。
---
import { Content, components } from '../content.mdx';
import Heading from '../Heading.astro';
---
<!-- # 記法のためのカスタムの <h1> を作成し、`content.mdx`で定義されたカスタムコンポーネントを適用します。 -->
<Content components={{...components, h1: Heading }} />
MarkdownとMDXの設定
Section titled MarkdownとMDXの設定AstroのMarkdownサポートは、活発なエコシステムを持つ強力なパースおよび処理ツールであるremarkによって提供されています。Pandocやmarkdown-itなどの他のMarkdownパーサーは、現在サポートされていません。
Astroは、GitHub-flavored Markdownと Smartypantsプラグインをデフォルトで適用します。これにより、テキストからクリッカブルリンクを生成したり、読みやすさのために引用をフォーマットしたりといった、いくつかの便利な機能が提供されます。
remarkがMarkdownをどのように解析するかは、astro.config.mjs
でカスタマイズできます。Markdownの設定オプションの全リストをご覧ください。
Markdownプラグイン
Section titled MarkdownプラグインAstroは、MarkdownおよびMDXのためのサードパーティのremarkおよびrehypeプラグインの追加をサポートしています。これらのプラグインにより、目次の自動生成、アクセス可能な絵文字ラベルの適用など、新しい機能でMarkdownを拡張できます。
人気のあるプラグインはawesome-remarkとawesome-rehypeを参照するのがおすすめです。具体的なインストール方法については、各プラグインのREADMEをご覧ください。
この例では、Astroのデフォルトプラグインを維持したまま、MarkdownとMDXにremark-toc
を適用し、MDXのみにrehype-accessible-emojis
を適用しています。
import { defineConfig } from 'astro/config';
import remarkToc from 'remark-toc';
import { rehypeAccessibleEmojis } from 'rehype-accessible-emojis';
export default {
markdown: {
// .md と .mdx ファイルに適用
remarkPlugins: [remarkToc],
// remark-gfm と remark-smartypants を保持
extendDefaultPlugins: true,
},
integrations: [mdx({
// .mdx ファイルのみに適用
rehypePlugins: [rehypeAccessibleEmojis],
})],
}
例:front-matterの挿入
Section titled 例:front-matterの挿入remarkやrehypeのプラグインを使用することで、すべてのMarkdownファイルやMDXファイルにfrontmatterプロパティを追加できます。
-
プラグインの
file
引数のdata.astro.frontmatter
プロパティにcustomProperty
を追加してください。example-remark-plugin.mjs export function exampleRemarkPlugin() { // すべての remark および rehype プラグインは、別の関数を返します。 return function (tree, file) { file.data.astro.frontmatter.customProperty = '生成されたプロパティ'; } }
-
このプラグインを
markdown
またはmdx
のインテグレーション設定に適用します。astro.config.mjs import { exampleRemarkPlugin } from './example-remark-plugin.mjs'; export default { markdown: { remarkPlugins: [exampleRemarkPlugin], extendDefaultPlugins: true, }, };
または
astro.config.mjs import { exampleRemarkPlugin } from './example-remark-plugin.mjs'; export default { integrations: [ mdx({ remarkPlugins: [exampleRemarkPlugin], }), ], }
これで、すべてのMarkdownまたはMDXファイルは、front-matterにcustomProperty
を持ち、Markdownのインポート時やレイアウトのAstro.props.frontmatter
プロパティから利用できるようになります。
例:読書時間の計算
Section titled 例:読書時間の計算remark pluginプラグインを使用すると、frontmatterに読了時刻を追加できます。次の2つのヘルパーがおすすめです。
reading-time
で読書時間(分)を計算します。mdast-util-to-string
はMarkdownからすべてのテキストを抽出します。
npm install reading-time mdast-util-to-string
これらのパッケージをremarkプラグインに適用すると、以下のようになります。
import getReadingTime from 'reading-time';
import { toString } from 'mdast-util-to-string';
export function remarkReadingTime() {
return function (tree, { data }) {
const textOnPage = toString(tree);
const readingTime = getReadingTime(textOnPage);
// readingTime.textは、読書時間(分)をフレンドリーな文字列として出力します。
// たとえば、"3 min read"
data.astro.frontmatter.minutesRead = readingTime.text;
};
}
このプラグインを設定ファイルに適用します。
import { remarkReadingTime } from './remark-reading-time.mjs';
export default {
markdown: {
remarkPlugins: [remarkReadingTime],
extendDefaultPlugins: true,
},
};
これにより、すべてのMarkdownドキュメントは計算されたminutesRead
を持つようになります。これを使用して、たとえばMarkdownレイアウトに読書時間を表示するバナーを含めることができます。
---
const { minutesRead } = Astro.props.frontmatter;
---
<html>
<head>...</head>
<body>
<p>{minutesRead}</p>
<slot />
</body>
</html>
シンタックスハイライト
Section titled シンタックスハイライトAstroは、ShikiとPrismをビルトインでサポートしています。これは、次のようなシンタックスハイライトを提供します。
- MarkdownまたはMDXファイルで使用されているすべてのコードフェンス(```)。
- 組み込みの
<Code />
コンポーネント (EN)内のコンテンツ (Shikiを使用)。 <Prism />
コンポーネント (EN)内のコンテンツ (Prismを使用)。
Shikiはデフォルトで有効になっており、github-dark
テーマであらかじめ設定されています。コンパイルされた出力は、余計なCSSクラス、スタイルシート、クライアントサイドJSのないインラインstyle
に限定されます。
Shikiの設定
Section titled Shikiの設定Shikiはデフォルトのシンタックスハイライトです。すべてのオプションはshikiConfig
オブジェクト経由で以下のように設定できます。
export default {
markdown: {
shikiConfig: {
// Shikiの組み込みテーマから選択(または独自のテーマを追加)
// https://github.com/shikijs/shiki/blob/main/docs/themes.md
theme: 'dracula',
// カスタム言語の追加
// 注:Shikiには.astroを含む無数の言語が内蔵されています。
// https://github.com/shikijs/shiki/blob/main/docs/languages.md
langs: [],
// 水平スクロールを防ぐために文字の折り返しを有効にする
wrap: true,
},
},
};
独自テーマの追加
Section titled 独自テーマの追加Shikiの定義済みテーマを使用する代わりに、ローカルファイルからカスタムテーマをインポートできます。
import { defineConfig } from 'astro/config';
import customTheme from './my-shiki-theme.json';
export default defineConfig({
markdown: {
shikiConfig: { theme: customTheme },
},
});
また、テーマ、ライトモードとダークモードの切り替え、CSS変数によるスタイリングについて詳しく調べるには、Shiki公式のテーマドキュメントを読むことをおすすめします。
デフォルトのシンタックスハイライトモードを変更する
Section titled デフォルトのシンタックスハイライトモードを変更するデフォルトを'prism'
に切り替えたい場合、またはシンタックスハイライトを完全に無効にしたい場合は、markdown.syntaxHighlighting
設定オブジェクトを使用できます。
export default {
markdown: {
// 'shiki'(デフォルト)、'prism'、またはハイライトを無効にする場合は false を指定します
syntaxHighlight: 'prism',
},
};
Prismの設定
Section titled Prismの設定Prismの使用を選択した場合、AstroはPrismのCSSクラスを代わりに適用します。なお、シンタックスハイライトを表示させるには、独自のCSSスタイルシートを用意する必要があります。
- 利用可能なPrismテーマから、あらかじめ用意されたスタイルシートを選択します。
- このスタイルシートをプロジェクトの
public/
ディレクトリに追加します。 - これをレイアウトコンポーネントの
<head>
に<link>
タグで読み込みます。(Prismの基本的な使い方を参照してください)
また、オプションや使い方については、Prismの対応言語一覧をご覧ください。
リモートにあるMarkdownの取得
Section titled リモートにあるMarkdownの取得Astroは主にプロジェクトディレクトリ内に保存されるローカルのMarkdownファイル用に設計されています。しかし、リモートソースからMarkdownを取得する必要がある特定のケースもあるかもしれません。たとえば、ウェブサイトを構築するとき(またはSSRを使用している場合、ユーザーがウェブサイトにリクエストを行うとき)、リモートAPIからMarkdownを取得してレンダリングする必要があるかもしれません。
Astroは、標準でリモートのMarkdownをサポートしていません! リモートのMarkdownを取得し、それをHTMLにレンダリングするには、npmから独自のMarkdownパーサーをインストールし、設定する必要があります。これは、カスタマイズしたAstroのビルトインMarkdownとMDXの設定をいずれからも継承しません。プロジェクトでこれを実装する前に、これらの制限を理解しておいてください。
---
// 例: Markdown をリモートAPIから取得し、
// それを実行時に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} />