Как создать блог на Next.js, который рендерит Markdown

Коротко: Next.js — это React-фреймворк для рендеринга и сборки. Markdown — простой текстовый формат для статей. Вместе они позволяют быстро сделать статический блог с контролем над контентом и выводом.
В этом материале вы найдете пошаговые инструкции, готовые шаблоны кода и операционные чеклисты для разработки, тестирования и развёртывания блога на Next.js, который читает статьи из локальной папки в формате Markdown.
Зачем это делать и когда не стоит
- Подходит, если вы хотите хранить статьи в Git и иметь полный контроль над шаблонами и рендерингом.
- Не подходит, если вам нужна панель управления для авторов без доступа к репозиторию — в этом случае лучше Headless CMS (Strapi, Sanity, Contentful) или готовые платформы (WordPress, Ghost).
Важно: Markdown хорош для простого контента. Если нужны интерактивные компоненты внутри постов, рассмотрите MDX.
Основные термины
- Markdown: лёгкий формат разметки для текста.
- Front matter: YAML-метаданные в начале файла Markdown (title, date, tags и т. п.).
- getStaticProps / getStaticPaths: функции Next.js для статической генерации.
Что потребует проект (технические требования)
- Node.js (рекомендую LTS — 16+).
- npm или Yarn.
- Next.js (create-next-app упростит старт).
1. Создание проекта Next.js
Запустите в терминале:
npx create-next-app markdown-blogЭто создаст каркас приложения. После завершения удалите лишний код из страницы /pages/index.js и оставьте минимальную структуру.
Пример минимального index.js:
import Head from 'next/head'
import styles from '../styles/Home.module.css'
export default function Home() {
return (
Create Next App
)
}2. Структура контента и файлы Markdown
Создайте в корне папку content (или posts). В ней будут храниться файлы .md.
Пример файла content/create-active-link-nextjs.md:
---
title: How To create an active link in Nextjs
description: Customizing active links using useRouter()
isPublished: true
publishedDate: 2022/07/22
tags:
- next
---
## Main contentСоветы по именованию:
- Имя файла станет частью URL (slug). Используйте короткие и понятные имена без пробелов.
- Дата в front matter может быть в формате YYYY-MM-DD или любой другой читаемой форме.
3. Установка зависимостей для парсинга Markdown
Установите react-markdown и gray-matter:
npm install react-markdown gray-matterКратко:
- gray-matter парсит front matter (YAML) и возвращает объект meta + content.
- react-markdown рендерит Markdown в React-компоненты безопасно.
4. Утилиты для работы с файлами Markdown
Создайте папку utils и файл utils/md.js. В нём разместите вспомогательные функции для чтения файлов, получения списка постов и содержимого.
Пример utils/md.js:
import fs from "fs";
import path from "path";
import matter from "gray-matter";
export const getPath = (folder) => {
return path.join(process.cwd(), `/${folder}`); // полный путь к папке
}
export const getFileContent = (filename, folder) => {
const POSTS_PATH = getPath(folder)
return fs.readFileSync(path.join(POSTS_PATH, filename), "utf8");
};
export const getAllPosts = (folder) => {
const POSTS_PATH = getPath(folder)
return fs
.readdirSync(POSTS_PATH) // получить файлы в директории
.filter((p) => /\.md?$/.test(p)) // только .md файлы
.map((fileName) => { // обработать каждый файл
const source = getFileContent(fileName, folder); // содержимое файла
const slug = fileName.replace(/\.md?$/, ""); // slug = имя файла без расширения
const { data } = matter(source); // front matter
return {
frontmatter: data,
slug: slug,
};
});
};
export const getAllPublished = (folder) => {
const posts = getAllPosts(folder)
const published = posts.filter((post) => {
return post.frontmatter.isPublished === true
})
return published
}
export const getSinglePost = (slug, folder) => {
const source = getFileContent(`${slug}.md`, folder);
const { data: frontmatter, content } = matter(source);
return {
frontmatter,
content,
};
};Пояснения:
- getAllPosts возвращает массив { frontmatter, slug } для каждой Markdown-статьи.
- getAllPublished фильтрует только опубликованные записи по ключу isPublished.
- getSinglePost возвращает frontmatter и raw content статьи по slug.
5. Отображение списка статей (index)
Next.js генерирует страницы статически с помощью getStaticProps. В index вы получите список опубликованных постов и отрисуете их.
Пример /pages/index.js:
import Head from "next/head";
import Link from "next/link";
import { getAllPublished } from "../utils/md";
import styles from '../styles/Home.module.css'
function Home({ posts }) {
return (
Create Next App
{posts.map((post) => (
[ {post.frontmatter.tags.join(", ")} ]
{post.frontmatter.title}
{post.frontmatter.description}
))}
);
}
export const getStaticProps = async () => {
const posts = getAllPublished("content");
return {
props: { posts },
};
};
export default Home;Примечание: убедитесь, что путь в getAllPublished соответствует папке контента (content или posts).
6. Динамические маршруты и отображение одной статьи
Создайте страницу /pages/posts/[slug].js. Для статической генерации нужны getStaticPaths и getStaticProps.
Пример getStaticPaths и getStaticProps:
import { getAllPublished, getSinglePost } from "../../utils/md";
export const getStaticPaths = async () => {
const paths = getAllPublished("content").map(({ slug }) => ({ params: { slug } }));
return {
paths,
fallback: false,
};
};
export const getStaticProps = async ({ params }) => {
const post = await getSinglePost(params.slug, "content");
return {
props: { ...post },
};
};Компонент для рендера поста с react-markdown:
import ReactMarkdown from 'react-markdown'
const Post = ({ content, frontmatter }) => {
return (
{frontmatter.tags.join(', ')}
{frontmatter.title}
{frontmatter.publishedDate}
{content}
);
};
export default Post;7. Подсветка синтаксиса и расширения Markdown
Если нужны кодовые блоки с подсветкой:
- Используйте rehype-прослойки (rehype-highlight) или prismjs вместе с rehype.
- Для полноценной интеграции компонентов внутри Markdown используйте MDX (next-mdx-remote или @next/mdx).
Короткое сравнение:
- react-markdown — простой и безопасный рендеринг Markdown.
- MDX — позволяет вставлять React-компоненты прямо в Markdown.
- Headless CMS — убирает необходимость редактировать репозиторий: контент хранится в UI.
8. Стилизация
Варианты:
- CSS-модули (по умолчанию в Next.js). Хорошо для компонентной стилизации.
- styled-components / emotion — CSS-in-JS для динамических стилей.
- Глобальные CSS-файлы для стилизации Markdown-контента (например, .markdown-content h2, p, code).
Совет: задайте единый контейнер .markdown и применяйте типографику и отступы для всех элементов.
9. SEO и Open Graph
- Используйте Head из next/head для задания title, meta description и Open Graph.
- Для постов в front matter храните краткое описание (description) и изображение (ogImage).
Пример вставки metadata в компонент поста:
import Head from 'next/head'
{frontmatter.title} — Мой блог
10. Тестирование и критерии приёмки
Критерии приёмки:
- Список постов корректно рендерится на главной странице.
- Каждая статья доступна по корректному урлу /posts/:slug.
- Статья рендерит front matter (title, date, tags) и содержимое Markdown.
- Для несуществующего slug возвращается 404 (fallback: false).
Тестовые сценарии:
- Создать файл в content, отметить isPublished: true, запустить сборку — проверить появление на главной.
- Установить isPublished: false — пост не должен отображаться.
- Добавить кодовый блок и проверить подсветку (если включено).
11. Развёртывание и оптимизация
- Статическая сборка Next.js отлично подходит для Vercel, Netlify, любой платформы, поддерживающей статические сайты.
- Для больших блогов с сотнями постов подумайте про инвалидацию кэша при новых публикациях или переход на ISR (Incremental Static Regeneration).
12. Варианты расширения (альтернативные подходы)
- MDX: для вставки React-компонентов в статьи.
- Headless CMS: если нужен редактор для контент-менеджеров.
- Git-backed CMS (Netlify CMS, TinaCMS): управлять контентом через интерфейс, хранить в Git.
- Полный статический генератор (Hugo, Jekyll) — быстрее сборка, но меньше гибкости React.
13. Уровни зрелости решения
- MVP: локальная папка content + react-markdown + gray-matter.
- Средний: добавить подсветку, SEO-мета, пагинацию, теги.
- Про: MDX, headless CMS, CI-пайплайн, ISR, интеграция аналитики и AMP (опционально).
14. Роли и чек-листы
Разработчик:
- Настроить файл utils/md.js и маршруты.
- Реализовать шаблон поста (шрифты, типографика).
- Настроить подсветку кода.
Контент-редактор:
- Писать статьи в Markdown с front matter.
- Проверять формат даты и теги.
Ops / DevOps:
- Настроить CI для билдов.
- Настроить развёртывание на Vercel/Netlify.
15. Частые ошибки и как их исправлять
- Неправильный путь к папке content: проверьте process.cwd() и путь в getPath.
- Ошибки парсинга front matter: проверьте корректность YAML (отступы, дефисы).
- Некорректные slugs: проверьте, что имя файла не содержит пробелов и специальных символов.
16. Примеры команд и полезные шаблоны
Сборка и запуск локально:
npm run dev
npm run build
npm startПример front matter для поста с ogImage:
---
title: Пример статьи
description: Краткое описание статьи
isPublished: true
publishedDate: 2025-01-10
tags:
- nextjs
- markdown
ogImage: /images/og-image.png
---
Контент поста...17. Короткий план внедрения (roadmap)
- Создать каркас Next.js и папку content.
- Реализовать utils/md.js и basic pages.
- Добавить react-markdown и проверить рендеринг.
- Подключить подсветку кода и MDX при необходимости.
- Настроить CI и развернуть на Vercel.
18. Пример принятия решения: использовать MDX или нет
- Если вам нужны компоненты в статьях — MDX.
- Если нужны только тексты и простая разметка — react-markdown.
Mermaid диаграмма принятия (если нужна визуализация):
flowchart TD
A[Нужны React-компоненты в статьях?] -->|Да| B[Использовать MDX]
A -->|Нет| C[Использовать react-markdown]
B --> D[Добавить поддержку компиляции MDX]
C --> E[Добавить rehype/remark плагины при необходимости]19. Безопасность и приватность
- Не рендерите небезопасный HTML напрямую без санитайза.
- Проверяйте загружаемые пути для изображений (чтобы предотвратить SSRF в редких конфигурациях).
- Если вы храните персональные данные в постах, учитывайте требования локального законодательства по хранению и удалению данных.
20. Краткое резюме
- Next.js + Markdown — быстрый путь к собственному блогу с полным контролем.
- react-markdown + gray-matter — базовая связка для рендеринга и парсинга.
- Для более сложных задач используйте MDX или Headless CMS.
Важное: начните с минимального набора, затем постепенно добавляйте подсветку, SEO и CI. Это снизит риски и ускорит обратную связь.
Похожие материалы
Исправить ошибку VLC «Ввод не может быть открыт»
Остановить автозагрузку приложений на Samsung
Тайм‑лапсы в Procreate: запись и экспорт
Как скопировать DVD на Mac — защищённые и незашищённые диски
Как хакеры взламывают автомобили и как защититься