Перейти к содержимому

Эта интеграция Astro включает использование Markdoc для создания компонентов, страниц и записей коллекций контента.

Markdoc позволяет расширять Markdown с помощью компонентов Astro. Если у вас уже есть контент, написанный в Markdoc, эта интеграция позволит перенести эти файлы в проект Astro через коллекции контента.

Astro включает команду astro add для автоматической настройки официальных интеграций. Если вы предпочитаете, вы можете установить интеграции вручную.

Запустите одну из следующих команд в новом окне терминала.

Окно терминала
npx astro add markdoc

Если у вас возникнут какие-либо проблемы, не стесняйтесь сообщать нам о них на GitHub и попробуйте выполнить шаги ручной установки ниже.

Сначала установите пакет @astrojs/markdoc:

Окно терминала
npm install @astrojs/markdoc

Затем подключите интеграцию в вашем astro.config.* через свойство integrations:

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

Если вы используете VS Code, есть официальное расширение языка Markdoc с подсветкой синтаксиса и автодополнением для настроенных тегов. Подробнее см. языковой сервер на GitHub.

Чтобы настроить расширение, создайте файл markdoc.config.json в корне проекта со следующим содержимым:

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

Укажите markdoc.config.mjs как файл конфигурации через объект schema и задайте, где хранятся Markdoc файлы, через path. Поскольку Markdoc используется только с коллекциями контента, удобно указывать src/content.

Markdoc файлы можно использовать только внутри коллекций контента. Добавляйте записи в любую коллекцию, используя расширение .mdoc:

  • Директорияsrc/
    • Директорияcontent/
      • Директорияdocs/
        • why-markdoc.mdoc
        • quick-start.mdoc

Затем запрашивайте вашу коллекцию через API коллекций контента:

src/pages/why-markdoc.astro
---
import { getEntry, render } from 'astro:content';
const entry = await getEntry('docs', 'why-markdoc');
const { Content } = await render(entry);
---
<!--Access frontmatter properties with `data`-->
<h1>{entry.data.title}</h1>
<!--Render Markdoc contents with the Content component-->
<Content />
Подробнее см. в документации по коллекциям контента Astro.

Иногда нужно передать переменные в контент. Это полезно, например, для SSR-параметров, A/B тестов и т.п.

Переменные можно передать как пропсы в компонент Content:

src/pages/why-markdoc.astro
---
import { getEntry, render } from 'astro:content';
const entry = await getEntry('docs', 'why-markdoc');
const { Content } = await render(entry);
---
<!--Pass the `abTest` param as a variable-->
<Content abTestGroup={Astro.params.abTestGroup} />

Теперь abTestGroup доступен как переменная в docs/why-markdoc.mdoc:

src/content/docs/why-markdoc.mdoc
{% if $abTestGroup === 'image-optimization-lover' %}
Let me tell you about image optimization...
{% /if %}

Чтобы сделать переменную глобальной для всех Markdoc файлов, можно использовать атрибут variables в markdoc.config.mjs|ts:

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

Чтобы получить доступ к frontmatter, можно передать data записи как переменную при рендеринге:

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

Теперь это доступно как $frontmatter в Markdoc.

@astrojs/markdoc предоставляет опции конфигурации, чтобы использовать возможности Markdoc и подключать UI-компоненты к вашему контенту.

Использование компонентов Astro как тегов Markdoc

Заголовок раздела «Использование компонентов Astro как тегов Markdoc»

Вы можете настроить теги Markdoc, которые будут сопоставлены с компонентами .astro. Добавьте новый тег, создав файл markdoc.config.mjs|ts в корне проекта и настроив tags.

Этот пример рендерит компонент Aside и позволяет передавать проп type как строку:

markdoc.config.mjs
import { defineMarkdocConfig, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
tags: {
aside: {
render: component('./src/components/Aside.astro'),
attributes: {
// Markdoc requires type defs for each attribute.
// These should mirror the `Props` type of the component
// you are rendering.
// See Markdoc's documentation on defining attributes
// https://markdoc.dev/docs/attributes#defining-attributes
type: { type: String },
},
},
},
});

Этот компонент можно использовать в Markdoc файлах через тег {% aside %}. Дочерний контент будет передан в слот по умолчанию:

# Welcome to Markdoc 👋
{% aside type="tip" %}
Use tags like this fancy "aside" to add some _flair_ to your docs.
{% /aside %}

Теги и nodes ограничены .astro файлами. Чтобы встроить клиентские UI-компоненты, используйте обертку .astro, которая рендерит framework-компонент с нужной директивой client:.

Этот пример оборачивает React компонент Aside.tsx в компонент ClientAside.astro:

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

Этот Astro компонент можно передать в render для любого тега или node в конфигурации:

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

Компоненты Astro из npm пакетов и TypeScript файлов

Заголовок раздела «Компоненты Astro из npm пакетов и TypeScript файлов»

Иногда нужно использовать Astro компоненты, доступные как именованные экспорты из TypeScript/JavaScript файлов. Это распространено для npm пакетов и дизайн-систем.

Вы можете передать имя экспорта вторым аргументом в component():

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

Внутри будет сгенерирован следующий import:

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

Тег {% partial /%} позволяет рендерить другие .mdoc файлы внутри Markdoc контента.

Это удобно для переиспользования фрагментов между документами и позволяет иметь .mdoc файлы, которые не соответствуют схеме коллекции.

Пример partial файла с футером для записей блога:

src/content/blog/_footer.mdoc
Social links:
- [Twitter / X](https://twitter.com/astrodotbuild)
- [Discord](https://astro.build/chat)
- [GitHub](https://github.com/withastro/astro)

Используйте {% partial /%} внизу записи блога. В атрибут file передайте путь к файлу (относительный путь или alias):

src/content/blog/post.mdoc
# My Blog Post
{% partial file="./_footer.mdoc" /%}

@astrojs/markdoc предоставляет расширения Shiki и Prism для подсветки блоков кода.

Подключите расширение shiki() в extends Markdoc конфигурации. Опционально можно передать объект конфигурации shiki:

markdoc.config.mjs
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
import shiki from '@astrojs/markdoc/shiki';
export default defineMarkdocConfig({
extends: [
shiki({
// Choose from Shiki's built-in themes (or add your own)
// Default: 'github-dark'
// https://shiki.style/themes
theme: 'dracula',
// Enable word wrap to prevent horizontal scrolling
// Default: false
wrap: true,
// Pass custom languages
// Note: Shiki has countless langs built-in, including `.astro`!
// https://shiki.style/languages
langs: [],
}),
],
});

Подключите prism() в extends:

markdoc.config.mjs
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
import prism from '@astrojs/markdoc/prism';
export default defineMarkdocConfig({
extends: [prism()],
});
О настройке стилей Prism см. в руководстве по подсветке синтаксиса.

Вы можете захотеть рендерить стандартные элементы Markdown (например параграфы или выделение) как Astro компоненты. Для этого можно настроить Markdoc node. Если node принимает атрибуты, они будут доступны как пропсы.

Пример: рендерить blockquote через кастомный Quote.astro:

markdoc.config.mjs
import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
nodes: {
blockquote: {
...nodes.blockquote, // Apply Markdoc's defaults for other options
render: component('./src/components/Quote.astro'),
},
},
});

@astrojs/markdoc автоматически добавляет anchor-ссылки к заголовкам и генерирует список headings через API коллекций контента. Чтобы дополнительно настроить, как рендерятся заголовки, можно применить Astro компонент как Markdoc node.

Пример: рендерить заголовки компонентом Heading.astro:

markdoc.config.mjs
import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
nodes: {
heading: {
...nodes.heading, // Preserve default anchor link generation
render: component('./src/components/Heading.astro'),
},
},
});

Все заголовки Markdown будут рендерить Heading.astro и передавать следующие attributes как пропсы:

  • level: number уровень заголовка 1 - 6
  • id: string id, сгенерированный из текста заголовка (соответствует slug, который генерируется функцией render())

Например, ### Level 3 heading! передаст level: 3 и id: 'level-3-heading'.

Пользовательские компоненты изображений

Заголовок раздела «Пользовательские компоненты изображений»

Компонент <Image /> из Astro нельзя использовать напрямую в Markdoc. Однако можно настроить Astro компонент, чтобы он переопределял стандартный image node (когда используется ![]()), или создать пользовательский тег Markdoc для изображения, чтобы указывать дополнительные атрибуты.

Чтобы переопределить стандартный image node, настройте .astro компонент, который будет рендериться вместо <img>.

  1. Создайте компонент MarkdocImage.astro, который передаст src и alt в <Image />:

    src/components/MarkdocImage.astro
    ---
    import type { ImageMetadata } from "astro";
    import { Image } from "astro:assets";
    interface Props {
    src: ImageMetadata;
    alt: string;
    }
    const { src, alt } = Astro.props;
    ---
    <Image src={src} alt={alt} />
  2. Для удаленных изображений <Image /> требует width и height, которые нельзя передать синтаксисом ![](). Чтобы избежать ошибок, отрендерите обычный <img>, если src - это URL строкой:

    src/components/MarkdocImage.astro
    ---
    import type { ImageMetadata } from "astro";
    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, чтобы переопределить image node и рендерить MarkdocImage.astro:

    markdoc.config.mjs
    import { defineMarkdocConfig, nodes, component } from '@astrojs/markdoc/config';
    export default defineMarkdocConfig({
    nodes: {
    image: {
    ...nodes.image, // Apply Markdoc's defaults for other options
    render: component('./src/components/MarkdocImage.astro'),
    },
    },
    });
  4. Теперь синтаксис ![]() в любом .mdoc будет использовать <Image /> для локальных изображений. Удаленные изображения по-прежнему можно использовать, но они будут рендериться как <img>.

    src/content/blog/post.mdoc
    <!-- Optimized by <Image /> -->
    ![A picture of a cat](/cat.jpg)
    <!-- Unoptimized <img> -->
    ![A picture of a dog](https://example.com/dog.jpg)

Создать пользовательский тег изображения Markdoc

Заголовок раздела «Создать пользовательский тег изображения Markdoc»

Тег image в Markdoc позволяет задавать дополнительные атрибуты, которые нельзя выразить через ![](). Например, пользовательские image-теги позволяют использовать <Image /> для удаленных изображений, которым нужны width и height.

Следующие шаги создают пользовательский image-тег, который рендерит <figure> с подписью и оптимизирует изображение через <Image />.

  1. Создайте компонент MarkdocFigure.astro:

    src/components/MarkdocFigure.astro
    ---
    import type { ImageMetadata } from "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. Настройте кастомный image-тег:

    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. Используйте image в .mdoc:

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

Файл markdoc.config.mjs|ts принимает все опции конфигурации Markdoc, включая теги и функции.

Вы можете передать эти опции в defineMarkdocConfig():

markdoc.config.mjs
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 контента:

¡Hola {% getCountryEmoji("spain") %}!
Смотрите документацию Markdoc для подробностей о переменных и функциях.

По умолчанию Markdoc оборачивает документ в <article>. Это можно изменить в node document. Можно указать имя HTML элемента или null, чтобы убрать обертку:

markdoc.config.mjs
import { defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';
export default defineMarkdocConfig({
nodes: {
document: {
...nodes.document, // Apply defaults for other options
render: null, // default 'article'
},
},
});

Интеграция Astro Markdoc отвечает за настройку опций Markdoc и возможностей, которые недоступны только через markdoc.config.js.

Тип: boolean
По умолчанию: false

Добавлено в: @astrojs/markdoc@0.4.4

Позволяет писать HTML-разметку рядом с Markdoc тегами и nodes.

По умолчанию Markdoc не распознает HTML-разметку как семантический контент.

Чтобы получить опыт, более похожий на Markdown, где можно использовать HTML элементы внутри контента, установите allowHTML:true в опциях интеграции markdoc.

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

Тип: boolean
По умолчанию: false

Добавлено в: @astrojs/markdoc@0.7.0

По умолчанию любой контент с отступом в четыре пробела трактуется как блок кода. Это затрудняет использование произвольных уровней отступов для улучшения читабельности сложных документов.

При использовании вложенных тегов Markdoc бывает полезно делать отступы внутри тегов, чтобы уровень вложенности был понятен. Для поддержки произвольных отступов нужно отключить code blocks, основанные на отступах, и изменить несколько правил парсинга. Это можно сделать через ignoreIndentation.

astro.config.mjs
import { defineConfig } from 'astro/config';
import markdoc from '@astrojs/markdoc';
export default defineConfig({
// ...
integrations: [markdoc({ ignoreIndentation: true })],
});
# Welcome to Markdoc with indented tags 👋
# Note: Can use either spaces or tabs for indentation
{% custom-tag %}
{% custom-tag %} ### Tags can be indented for better readability
{% another-custom-tag %}
This is easier to follow when there is a lot of nesting
{% /another-custom-tag %}
{% /custom-tag %}
{% /custom-tag %}

Дополнительные интеграции

UI-фреймворки

Адаптеры

Другие интеграции