Запилил кросс-фреймворк Markdown/MDX парсер, чтобы не мучаться с контентом
- пятница, 30 января 2026 г. в 00:00:08
Всем привет!
Долго я возился с маркдауном в своих проектах и, честно говоря, знатно подгорел. Первая проблема — это вечный выбор библиотеки.
С одной стороны, есть «конструкторы» типа unified, remark и rehype. Штуки мощные, но настраивать весь этот AST-конвейер и систему плагинов — это какой-то оверхед и лишняя сложность, имхо.
С другой стороны, есть @next/mdx, который вроде и ок, но слишком завязан на страницах и вообще не умеет работать на клиенте.
Раньше я обычно выбирал что-то вроде markdown-to-jsx или react-markdown.
DX у них приятнее, работают и на клиенте, и на сервере, весят мало.
Но вот беда: они «из коробки» не переваривают HTML или MDX, и ты снова вязнешь в настройке плагинов. А если добавить туда i18n (типа i18next или next-intl), начинается настоящий ад. Куча if/else в коде, чтобы отрендерить нужный язык, и бандл раздувается до небес. Плюс вечные косяки с front-matter. Ну и до недавнего времени всё это было только для React.
В общем, решил я написать свое решение для intlayer. Чтобы просто работало.
> К слову, за основу я взял форк markdown-to-jsx v7.7.14 (от quantizor), который базируется на simple-markdown v0.2.2 (от Khan Academy).
Когда пилил этот парсер, ставил перед собой такие цели:
- Максимально легкий вес
- Кросс-фреймворковость (React, Vue, Svelte, Angular, Solid, Preact)
- Простая настройка: никаких бесконечных цепочек плагинов
- Поддержка SSR и клиентского рендеринга
- Настройка на уровне провайдера: можно легко прокинуть свои компоненты из дизайн-системы
- Компонентный подход: полный контроль над рендерингом каждой части приложения
- Типобезопасность (front-matter возвращается как типизированный объект, типизация пропсов компонентов)
- Заточен под i18n (оптимизированная загрузка контента для разных языков)
- Валидация front-matter через схемы zod
Демо:
Можно юзать как обычную утилиту:
import { renderMarkdown } from "react-intlayer"; // Для других фреймворков аналогично: vue-intlayer, svelte-intlayer и т.д.
// Простая функция рендера (возвращает JSX/ноды, а не просто строку)
renderMarkdown("### Мой заголовок", {
components: { h3: (props) => <h3 className="text-xl" {...props} /> },
});Или через компоненты и хуки:
import {
MarkdownRenderer,
MarkdownProvider,
useMarkdownRenderer,
} from "react-intlayer";
// В виде компонента
<MarkdownRenderer components={{ h3: MyCustomH3 }}>
### Мой заголовок
</MarkdownRenderer>;
<MarkdownProvider components={{ h3: MyCustomH3 }}>{children}</MarkdownProvider>;
// В виде хука с контекстом провайдера
const render = useMarkdownRenderer();
return <div>{render("# Привет")}</div>;Но настоящая магия начинается при использовании с декларацией контента Intlayer (полное разделение логики и данных):
// ./myMarkdownContent.content.ts
import { md } from "intlayer";
export default {
key: "my-content",
content: md("## Это мой мультиязычный MD"),
// Загрузка из файловой системы
// content: md(readFileSync("./myMarkdown.md", "utf8")),
// Загрузка по API
// content: md(fetch("https://api.example.com/content").then((res) => res.text())),
};В самом компоненте это выглядит как обычная переменная — никакого ручного парсинга:
const { myContent } = useIntlayer("my-content");
return (
<div>
{myContent} {/* Рендерится автоматически с глобальным конфигом */}
{/* или */}
{/* Можно переопределить компоненты на лету */}
{myContent.use({
h2: (props) => <h2 className="text-blue-500" {...props} />,
})}
</div>
);В чем, собственно, инновация?
- Реально универсальный: одна и та же логика для React, Vue, Svelte и прочих.
- Легкий MDX-подобный компилятор: отлично работает на Edge и сервере.
- Нулевое время загрузки: контент подгружается на этапе билда (будь то fs или fetch).
- Удобная организация: можно легко переиспользовать куски маркдауна между разными доками.
- Типобезопасный парсинг front-matter (как это делал покойный contentLayer).
Для чего это подходит?
- Блоги / Документация / Политика конфиденциальности / Условия использования
- Динамические данные с бэкенда
- Вынос контента страниц в Headless CMS
- Прямая загрузка .md файлов
Сделал это от безысходности и усталости от текущих решений. Знакомо? Расскажите, как вы сейчас готовите Markdown в своих проектах?