MDX — это расширение Markdown, которое позволяет включать JSX-компоненты прямо в тексты. В отличие от стандартного Markdown, MDX превращает статический контент в интерактивный, динамически управляемый через React-компоненты.
import { MyButton } from './components/MyButton.mdx';
export default function BlogPost() {
return (
<div>
<h1>Заголовок статьи</h1>
<p>Простой текст с возможностью вставки компонента:</p>
<MyButton>Нажми меня</MyButton>
</div>
);
}
MDX позволяет импортировать React-компоненты и использовать их как часть разметки. Любой компонент можно вставить с использованием стандартного синтаксиса JSX:
import Alert from './components/Alert';
# Новость дня
<Alert type="warning">
Важное уведомление для всех пользователей!
</Alert>
Текст статьи продолжается после компонента.
Ключевой момент: MDX компилируется в React-компоненты, поэтому можно использовать все возможности JSX: условные рендеринги, циклы, пропсы, стили и контекст.
Для создания блога на MDX обычно используют следующую структуру:
/src
/posts
first-post.mdx
second-post.mdx
/components
Layout.js
Header.js
Footer.js
/pages
index.js
[slug].js
.mdx.Для динамического отображения статей в блоге на Next.js или Remix необходимо:
@next/mdx или
@mdx-js/react.Пример загрузки MDX-файла в Next.js:
import { MDXRemote } from 'next-mdx-remote';
import { serialize } from 'next-mdx-remote/serialize';
import fs from 'fs';
import path from 'path';
export default function Post({ source }) {
return <MDXRemote {...source} />;
}
export async function getStaticProps() {
const filePath = path.join(process.cwd(), 'src/posts/first-post.mdx');
const fileContent = fs.readFileSync(filePath, 'utf8');
const mdxSource = await serialize(fileContent);
return { props: { source: mdxSource } };
}
MDXProviderMDXProvider позволяет определять, как будут отображаться
стандартные элементы Markdown. Например, можно изменить визуальное
оформление заголовков, параграфов и ссылок:
import { MDXProvider } from '@mdx-js/react';
import CustomH1 from './components/CustomH1';
import CustomLink from './components/CustomLink';
const components = {
h1: CustomH1,
a: CustomLink,
};
export default function App({ children }) {
return <MDXProvider components={components}>{children}</MDXProvider>;
}
Это особенно полезно для единого стиля блога, где каждый заголовок и ссылка имеют фирменный дизайн.
MDX позволяет передавать данные через пропсы, делая статьи интерактивными и зависимыми от состояния приложения:
<MyWidget user={user} showDetails={true} />
В этом примере user передается из React-компонента, а
MDX используется для рендеринга динамического контента.
MDX сохраняет все преимущества Markdown:
#, ##, ###)-, *, 1.)При этом любой Markdown-элемент можно заменить на кастомный
React-компонент через MDXProvider.
Для больших блогов рекомендуется:
next-mdx-remote для динамической загрузки
статей.getStaticProps или
getStaticPaths), чтобы уменьшить нагрузку на клиент.<Gallery images={['img1.png', 'img2.png']} />
<Video src="intro.mp4" />
MDX отлично интегрируется с Next.js для генерации статических страниц. Можно автоматически строить SEO-мета-теги:
export async function getStaticPaths() {
const posts = ['first-post', 'second-post'];
const paths = posts.map(slug => ({ params: { slug } }));
return { paths, fallback: false };
}
export async function getStaticProps({ params }) {
const filePath = `src/posts/${params.slug}.mdx`;
const fileContent = fs.readFileSync(filePath, 'utf8');
const mdxSource = await serialize(fileContent);
return { props: { source: mdxSource } };
}
Каждая статья становится отдельной страницей с собственным маршрутом и метаданными для поисковых систем.
.mdx файлах.MDXProvider и
MDXRemote.Такой подход позволяет создавать гибкий, расширяемый блог с интерактивными элементами и единым дизайном.