import { FileTree } from '@astrojs/starlight/components'; import PackageManagerTabs from '/components/tabs/PackageManagerTabs.astro'; import { Steps } from '@astrojs/starlight/components'; import ReadMore from '/components/ReadMore.astro';

このAstroインテグレーションは、Markdocを使用してコンポーネント、ページ、およびコンテンツコレクションのエントリを作成できるようにします。

なぜMarkdocなのか

Markdocを使用すると、AstroコンポーネントでMarkdownを強化できます。Markdocで作成された既存のコンテンツがある場合、このインテグレーションを使用すると、コンテンツコレクションを使用してそれらのファイルをAstroプロジェクトに持ち込むことができます。

インストール

Astroには、公式インテグレーションのセットアップを自動化するためのastro addコマンドが含まれています。もしよろしければ、手動でインテグレーションをインストールすることもできます。

新しいターミナルウィンドウで次のいずれかのコマンドを実行します。

問題が発生した場合は、GitHubで報告してください。そして、以下の手動インストール手順を試してください。

手動インストール

まず、@astrojs/markdocパッケージをインストールします。

次に、integrationsプロパティを使用して、インテグレーションをastro.config.*ファイルに適用します。

js
import { defineConfig } from 'astro/config';import markdoc from '@astrojs/markdoc';export default defineConfig({  // ...  integrations: [markdoc()],});

VS Codeエディタの統合

VS Codeを使用している場合は、構成されたタグの構文ハイライトとオートコンプリートを含む公式のMarkdoc言語拡張機能があります。詳細については、GitHubの言語サーバーを参照してください。

拡張機能をセットアップするには、プロジェクトのルートにmarkdoc.config.jsonファイルを作成し、次の内容を含めます。

json
[  {    "id": "my-site",    "path": "src/content",    "schema": {      "path": "markdoc.config.mjs",      "type": "esm",      "property": "default",      "watch": true    }  }]

markdoc.config.mjsschemaオブジェクトを持つ設定ファイルとして設定し、pathプロパティを使用してMarkdocファイルが保存されている場所を定義します。Markdocはコンテンツコレクションに固有であるため、src/contentを使用できます。

使い方

Markdocファイルは、コンテンツコレクション内でのみ使用できます。.mdoc拡張子を使用して、任意のコンテンツコレクションにエントリを追加します。

次に、コンテンツコレクションAPIを使用してコレクションをクエリします。

astro
---import { getEntry, render } from 'astro:content';const entry = await getEntry('docs', 'why-markdoc');const { Content } = await render(entry);---<!--dataでフロントマターのプロパティにアクセス--><h1>{entry.data.title}</h1><!--ContentコンポーネントでMarkdocのコンテンツをレンダリング--><Content />

Astroコンテンツコレクションのドキュメントで詳細を確認してください。

Markdoc変数を渡す

コンテンツに変数を渡す必要がある場合があります。これは、A/BテストなどのSSRパラメータを渡す場合に便利です。

変数は、Contentコンポーネントを介してプロップとして渡すことができます。

astro
---import { getEntry, render } from 'astro:content';const entry = await getEntry('docs', 'why-markdoc');const { Content } = await render(entry);---<!--abTestパラメータをを渡す--><Content abTestGroup={Astro.params.abTestGroup} />

これで、abTestGroupdocs/why-markdoc.mdocで変数として利用できます。

md
{% if $abTestGroup === 'image-optimization-lover' %}画像の最適化についてお話ししましょう...{% /if %}

すべてのMarkdocファイルにグローバルな変数を作成するには、markdoc.config.mjs|tsからvariables属性を使用できます。

js
import { defineMarkdocConfig } from '@astrojs/markdoc/config';export default defineMarkdocConfig({  variables: {    environment: process.env.IS_PROD ? 'prod' : 'dev',  },});

Markdocコンテンツからフロントマターにアクセスする

フロントマターにアクセスするには、コンテンツをレンダリングする場所でエントリのdataプロパティをを渡すことができます。

astro
---import { getEntry, render } from 'astro:content';const entry = await getEntry('docs', 'why-markdoc');const { Content } = await render(entry);---<Content frontmatter={entry.data} />

これは、Markdocで$frontmatterとしてアクセスできるようになりました。

コンポーネントのレンダリング

@astrojs/markdocは、Markdocのすべての機能を使用し、UIコンポーネントをコンテンツに接続するための設定オプションを提供します。

AstroコンポーネントをMarkdocタグとして使用する

.astroコンポーネントにマッピングされるMarkdocタグを設定できます。プロジェクトのルートにmarkdoc.config.mjs|tsファイルを作成し、tag属性を設定することで、新しいタグを追加できます。

この例では、Asideコンポーネントをレンダリングし、typepropを文字列として渡すことができます。

js
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';export default defineMarkdocConfig({  tags: {    aside: {      render: component('./src/components/Aside.astro'),      attributes: {        // Markdocは各属性に型定義を要求します。        // これらは、レンダリングしているコンポーネントの        // `Props`型を反映する必要があります。        // 属性の定義に関するMarkdocのドキュメントを参照してください        // https://markdoc.dev/docs/attributes#defining-attributes        type: { type: String },      },    },  },});

このコンポーネントは、{% aside %}タグを使用してMarkdocファイルで使用できるようになりました。子はコンポーネントのデフォルトスロットに渡されます。

md
# Markdocへようこそ👋{% aside type="tip" %}この派手な「aside」のようなタグを使用して、ドキュメントに_センス_を加えてください。{% /aside %}

クライアントサイドUIコンポーネントを使用する

タグとノードは.astroファイルに制限されています。クライアントサイドUIコンポーネントをMarkdocに埋め込むには、フレームワークコンポーネントをレンダリングするラッパー.astroコンポーネントを使用し、目的のclient:ディレクティブを指定します。

この例では、React Aside.tsxコンポーネントをClientAside.astroコンポーネントでラップします。

astro
---import Aside from './Aside';---<Aside {...Astro.props} client:load />

このAstroコンポーネントは、設定内の任意のタグまたはノードrenderpropに渡すことができるようになりました。

js
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';export default defineMarkdocConfig({  tags: {    aside: {      render: component('./src/components/ClientAside.astro'),      attributes: {        type: { type: String },      },    },  },});

npmパッケージとTypeScriptファイルからAstroコンポーネントを使用する

TypeScriptまたはJavaScriptファイルから名前付きエクスポートとして公開されているAstroコンポーネントを使用する必要がある場合があります。これは、npmパッケージやデザインシステムを使用する場合によくあります。

component()関数の2番目の引数としてインポート名を渡すことができます。

js
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';export default defineMarkdocConfig({  tags: {    tabs: {      render: component('@astrojs/starlight/components', 'Tabs'),    },  },});

これにより、内部で次のインポートステートメントが生成されます。

ts
import { Tabs } from '@astrojs/starlight/components';

Markdocパーシャル

{% partial /%}タグを使用すると、Markdocコンテンツ内に他の.mdocファイルをレンダリングできます。

これは、複数のドキュメントでコンテンツを再利用する場合に便利で、コレクションスキーマに従わない.mdocコンテンツファイルを持つことができます。

:::tip パーシャルファイルまたはディレクトリにはアンダースコア_プレフィックスを使用します。これにより、パーシャルがコンテンツコレクションクエリから除外されます。 :::

この例は、ブログコレクションエントリ内で使用するフッターのMarkdocパーシャルを示しています。

md
ソーシャルリンク:- [Twitter / X](https://twitter.com/astrodotbuild)- [Discord](https://astro.build/chat)- [GitHub](https://github.com/withastro/astro)

{% partial /%}タグを使用して、ブログ投稿エントリの下部にフッターをレンダリングします。相対パスまたはインポートエイリアスを使用して、ファイルへのパスを指定してfile属性を適用します。

md
# 私のブログ投稿{% partial file="./_footer.mdoc" /%}

構文のハイライト

@astrojs/markdocは、コードブロックをハイライトするためのShikiおよびPrism拡張機能を提供します。

Shiki

extendsプロパティを使用して、Markdoc設定にshiki()拡張機能を適用します。オプションで、shiki設定オブジェクトを渡すことができます。

js
import { defineMarkdocConfig } from '@astrojs/markdoc/config';import shiki from '@astrojs/markdoc/shiki';export default defineMarkdocConfig({  extends: [    shiki({      // Shikiの組み込みテーマから選択(または独自に追加)      // デフォルト: 'github-dark'      // https://shiki.style/themes      theme: 'dracula',      // 水平スクロールを防ぐためにワードラップを有効にする      // デフォルト: false      wrap: true,      // カスタム言語を渡す      // 注: Shikiには、`.astro`を含む無数の言語が組み込まれています!      // https://shiki.style/languages      langs: [],    }),  ],});

Prism

extendsプロパティを使用して、Markdoc設定にprism()拡張機能を適用します。

js
import { defineMarkdocConfig } from '@astrojs/markdoc/config';import prism from '@astrojs/markdoc/prism';export default defineMarkdocConfig({  extends: [prism()],});

Prismスタイルシートの設定については、構文ハイライトガイドを参照してください。

カスタムMarkdocノード/要素

段落や太字のテキストなどの標準的なMarkdown要素をAstroコンポーネントとしてレンダリングしたい場合があります。このために、Markdocノードを設定できます。特定のノードが属性を受け取る場合、それらはコンポーネントのプロップとして利用できます。

この例では、カスタムのQuote.astroコンポーネントを使用してブロッククオートをレンダリングします。

js
import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';export default defineMarkdocConfig({  nodes: {    blockquote: {      ...nodes.blockquote, // 他のオプションにはMarkdocのデフォルトを適用      render: component('./src/components/Quote.astro'),    },  },});

すべての組み込みノードと属性については、Markdocノードのドキュメントを参照してください。

カスタム見出し

@astrojs/markdocは、見出しにアンカーリンクを自動的に追加し、コンテンツコレクションAPIを介してheadingsのリストを生成します。見出しのレンダリング方法をさらにカスタマイズするには、AstroコンポーネントをMarkdocノードとして適用できます。

この例では、renderプロパティを使用してHeading.astroコンポーネントをレンダリングします。

js
import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';export default defineMarkdocConfig({  nodes: {    heading: {      ...nodes.heading, // デフォルトのアンカーリンク生成を維持      render: component('./src/components/Heading.astro'),    },  },});

すべてのMarkdown見出しはHeading.astroコンポーネントをレンダリングし、次のattributesをコンポーネントのプロップとして渡します。

  • level: number 見出しレベル1〜6
  • id: string 見出しのテキストコンテンツから生成されたid。これは、コンテンツrender()関数によって生成されたslugに対応します。

たとえば、見出し### レベル3の見出し!は、コンポーネントのプロップとしてlevel: 3id: 'level-3-heading'を渡します。

カスタム画像コンポーネント

Astroの<Image />コンポーネントは、Markdocで直接使用することはできません。ただし、ネイティブの![]()画像構文が使用されるたびにデフォルトの画像ノードを上書きするようにAstroコンポーネントを設定したり、追加の画像属性を指定できるカスタムMarkdocタグとして設定したりできます。

Markdocのデフォルト画像ノードを上書きする

デフォルトの画像ノードを上書きするには、標準の<img>の代わりにレンダリングされるように.astroコンポーネントを設定できます。

```astro title="src/components/MarkdocImage.astro" --- import { Image } from "astro:assets"; interface Props { src: ImageMetadata; alt: string; } const { src, alt } = Astro.props; --- <Image src={src} alt={alt} /> ```

2. <Image />コンポーネントには、![]()構文では提供できないリモート画像のwidthheightが必要です。リモート画像を使用する際のエラーを回避するには、リモートURLのsrcが見つかった場合に標準のHTML <img>タグをレンダリングするようにコンポーネントを更新します。

```astro title="src/components/MarkdocImage.astro" ins="| string" del={9} ins={10-12} --- import { Image } from "astro:assets"; interface Props { src: ImageMetadata | string; alt: string; } const { src, alt } = Astro.props; --- <Image src={src} alt={alt} /> { typeof src === 'string' ? <img src={src} alt={alt} /> : <Image src={src} alt={alt} /> } ```

3. Markdocを設定して、デフォルトの画像ノードを上書きし、MarkdocImage.astroをレンダリングします。

```js title="markdoc.config.mjs" import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config'; export default defineMarkdocConfig({ nodes: { image: { ...nodes.image, // 他のオプションにはMarkdocのデフォルトを適用 render: component('./src/components/MarkdocImage.astro'), }, }, }); ```

4. .mdocファイル内のネイティブ画像構文は、<Image />コンポーネントを使用してローカル画像を最適化するようになります。リモート画像は引き続き使用できますが、Astroの<Image />コンポーネントではレンダリングされません。

```md title="src/content/blog/post.mdoc" <!-- <Image />によって最適化 --> ![猫の写真](/cat.jpg) <!-- 最適化されていない<img> --> ![犬の写真](https://example.com/dog.jpg) ```

カスタムMarkdoc画像タグを作成する

Markdocのimageタグを使用すると、![]()構文では不可能な追加の属性を画像に設定できます。たとえば、カスタム画像タグを使用すると、widthheightが必要なリモート画像にAstroの<Image />コンポーネントを使用できます。

次の手順では、Astro <Image />コンポーネントを使用して画像を最適化し、キャプション付きの<figure>要素を表示するカスタムMarkdoc画像タグを作成します。

```astro title="src/components/MarkdocFigure.astro" --- // src/components/MarkdocFigure.astro import { Image } from "astro:assets"; interface Props { src: ImageMetadata | string; alt: string; width: number; height: number; caption: string; } const { src, alt, width, height, caption } = Astro.props; --- <figure> <Image {src} {alt} {width} {height} /> {caption && <figcaption>{caption}</figcaption>} </figure> ```

2. Astroコンポーネントをレンダリングするようにカスタム画像タグを設定します。

```ts title="markdoc.config.mjs" import { component, defineMarkdocConfig, nodes } from '@astrojs/markdoc/config'; export default defineMarkdocConfig({ tags: { image: { attributes: { width: { type: String, }, height: { type: String, }, caption: { type: String, }, ...nodes.image.attributes }, render: component('./src/components/MarkdocFigure.astro'), }, }, }); ```

3. Markdocファイルでimageタグを使用して、コンポーネントに必要なすべての属性を指定して、キャプション付きの図を表示します。

```md {% image src="./astro-logo.png" alt="Astro Logo" width="100" height="100" caption="a caption!" /%} ```

高度なMarkdoc設定

markdoc.config.mjs|tsファイルは、タグ関数など、すべてのMarkdoc設定オプションを受け入れます。

これらのオプションは、markdoc.config.mjs|tsファイルのデフォルトエクスポートから渡すことができます。

js
import { defineMarkdocConfig } from '@astrojs/markdoc/config';export default defineMarkdocConfig({  functions: {    getCountryEmoji: {      transform(parameters) {        const [country] = Object.values(parameters);        const countryToEmojiMap = {          japan: '🇯🇵',          spain: '🇪🇸',          france: '🇫🇷',        };        return countryToEmojiMap[country] ?? '🏳';      },    },  },});

これで、任意のMarkdocコンテンツエントリからこの関数を呼び出すことができます。

md
¡Hola {% getCountryEmoji("spain") %}!

コンテンツでの変数や関数の使用方法の詳細については、Markdocのドキュメントを参照してください。

ルートHTML要素を設定する

Markdocは、デフォルトでドキュメントを<article>タグでラップします。これは、document Markdocノードから変更できます。これは、ラッパー要素を削除したい場合は、HTML要素名またはnullを受け入れます。

js
import { defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';export default defineMarkdocConfig({  nodes: {    document: {      ...nodes.document, // 他のオプションにはデフォルトを適用      render: null, // デフォルトは'article'    },  },});

インテグレーション設定オプション

Astro Markdocインテグレーションは、markdoc.config.jsファイルでは利用できないMarkdocオプションと機能の設定を処理します。

allowHTML

Markdocタグやノードと並べてHTMLマークアップを記述できるようにします。

デフォルトでは、MarkdocはHTMLマークアップを意味のあるコンテンツとして認識しません。

HTML要素をコンテンツと並べて含めることができる、よりMarkdownらしいエクスペリエンスを実現するには、markdocインテグレーションオプションとしてallowHTML:trueを設定します。これにより、MarkdocマークアップでHTML解析が有効になります。

js
  import { defineConfig } from 'astro/config';  import markdoc from '@astrojs/markdoc';  export default defineConfig({    // ...    integrations: [markdoc({ allowHTML: true })],  });

:::caution allowHTMLが有効になっている場合、Markdocドキュメント内のHTMLマークアップは実際のHTML要素(<script>を含む)としてレンダリングされるため、XSSなどの攻撃ベクトルが可能になります。HTMLマークアップが信頼できるソースからのものであることを確認してください。 :::

ignoreIndentation

デフォルトでは、4つのスペースでインデントされたコンテンツはコードブロックとして扱われます。残念ながら、この動作により、複雑な構造を持つドキュメントの読みやすさを向上させるために任意のレベルのインデントを使用することが困難になります。

Markdocでネストされたタグを使用する場合、タグ内のコンテンツをインデントして、深さのレベルが明確になるようにすると便利です。任意のインデントをサポートするには、インデントベースのコードブロックを無効にし、インデントベースのコードブロックを考慮する他のいくつかのmarkdown-it解析ルールを変更する必要があります。これらの変更は、ignoreIndentationオプションを有効にすることで適用できます。

js
  import { defineConfig } from 'astro/config';  import markdoc from '@astrojs/markdoc';  export default defineConfig({    // ...    integrations: [markdoc({ ignoreIndentation: true })],  });
md
# インデントされたタグを持つMarkdocへようこそ👋# 注:インデントにはスペースまたはタブのいずれかを使用できます{% custom-tag %}{% custom-tag %} ### タグは読みやすくするためにインデントできます    {% another-custom-tag %}      ネストが多い場合にこれを追跡しやすくなります    {% /another-custom-tag %}{% /custom-tag %}{% /custom-tag %}