Как устроен сайт на MkDocs Material и GitHub Pages
Разбор того, что происходит от Markdown-файла до публикации сайта и что реально загружается в браузере при открытии страницы.
Введение
Когда я начинал делать SkillMatrix, задача выглядела довольно простой.
Есть папка с Markdown-файлами. Нужно превратить её в удобный сайт для чтения.
Сначала я даже написал собственный генератор на Python. Markdown превращался в HTML, работали шаблоны, постепенно появилась навигация, индекс страниц и оформление.
Но довольно быстро стало понятно, что я начинаю писать собственный статический генератор сайтов.
В итоге после перебора нескольких вариантов я остановился на MkDocs.
Не потому что это модный инструмент. А потому что он оказался самым простым и понятным способом получить полноценный сайт из обычной папки с Markdown-документами.
Сейчас сайт SkillMatrix работает на связке:
Markdown
↓
MkDocs
↓
Material Theme
↓
GitHub Pages
Разберёмся, что происходит внутри.
Что такое MkDocs
MkDocs — это статический генератор сайтов на Python.
Его задача очень простая:
Markdown → HTML
Во время сборки MkDocs читает все Markdown-файлы, генерирует HTML-страницы и складывает результат в отдельную папку.
После этого никакой Python больше не нужен.
Получается полностью статический сайт.
Что значит "статический"
Статический сайт — это набор готовых файлов:
index.html
page1.html
page2.html
main.css
bundle.js
search_index.json
Когда пользователь открывает страницу, сервер просто отдаёт эти файлы.
Никаких запросов к базе данных.
Никакой серверной логики.
Никакого PHP.
Никакого Django.
Никакого Flask.
Фактически GitHub Pages работает как обычное файловое хранилище.
Что такое Material for MkDocs
Многие думают, что MkDocs и Material — это одно и то же.
На самом деле нет.
- MkDocs отвечает за генерацию страниц.
- Material отвечает за внешний вид и пользовательский интерфейс.
Если убрать Material, останется просто набор HTML-страниц.
Material добавляет всё то, что делает документацию похожей на современный сайт.
Что Material делает автоматически
Из коробки появляются:
Навигация
Левое меню строится автоматически на основе структуры документации.
Манифест
Про CRM
├─ Что такое CRM
├─ Путь клиента
└─ Почему я занимаюсь CRM
Про ремонт
└─ Как я вешал зеркало
Оглавление страницы
Правая колонка строится из заголовков статьи.
Во что я верю
Честность важнее правоты
Роль ИИ
Что я собираю
Поиск
Поиск работает прямо в браузере.
- Без сервера.
- Без базы данных.
- Все статьи индексируются во время сборки.
Адаптивный интерфейс
- На телефоне меню превращается в выезжающую панель.
- На компьютере показываются две боковые колонки.
Темизация
Material умеет:
- светлую тему;
- тёмную тему;
- пользовательские цветовые схемы;
- переключение через localStorage.
Подсветка кода
Автоматически оформляет:
print("Hello")
Дополнительные возможности
Также Material добавляет:
- хлебные крошки;
- иконки;
- вкладки;
- предупреждения;
- карточки;
- диаграммы Mermaid;
- поддержку LaTeX;
- поиск по заголовкам.
По сути Material — это уже готовый фронтенд-фреймворк для документации.
Как устроен процесс публикации
Сборка выполняется командой:
mkdocs build
После этого создаётся папка:
site/
В ней лежит полностью готовый сайт.
Публикация через GitHub Pages
Для публикации используется команда:
mkdocs gh-deploy
Что происходит внутри:
- MkDocs выполняет сборку сайта.
- Создаёт временную ветку
gh-pages. - Копирует туда содержимое папки
site. - Делает commit.
- Отправляет изменения в GitHub.
- GitHub Pages начинает раздавать эти файлы.
Схема выглядит так:
Markdown
↓
mkdocs build
↓
site/
↓
mkdocs gh-deploy
↓
gh-pages
↓
GitHub Pages
↓
https://skillmatrix.ru
Никаких серверов я не арендую.
Никаких VPS не настраиваю.
Весь сайт живёт внутри GitHub Pages.
Что реально загружается при открытии страницы
Я снял HAR-лог главной страницы SkillMatrix и посмотрел реальные тайминги.
Полная загрузка страницы:
onLoad ≈ 440 мс
Для статического сайта это отличный результат.
Все загружаемые файлы
| Файл | Тип | Время | Размер |
|---|---|---|---|
| HTML-документ | document | 64 мс | 6.6 KB |
| main.css | stylesheet | 94 мс | 23.7 KB |
| Google Fonts CSS | stylesheet | 36 мс | 2.3 KB |
| bundle.js | script | 135 мс | 35.5 KB |
| Roboto Latin | font | 194 мс | 37.5 KB |
| Roboto Cyrillic | font | 101 мс | 19.6 KB |
| Roboto Symbols | font | 174 мс | 16.7 KB |
| Roboto Math | font | 91 мс | 36.3 KB |
| search_index.json | JSON | 65 мс | 28.5 KB |
| search worker | script | 70 мс | 0.15 KB |
| lunr stemmer | script | 80 мс | 1.5 KB |
| lunr.ru | script | 49 мс | 3.5 KB |
| favicon | image | 46 мс | 2.1 KB |
Общая статистика
| Параметр | Значение |
|---|---|
| Всего файлов | 13 |
| Общий вес | ~216 KB |
| Полная загрузка | ~440 мс |
| Самый тяжёлый файл | bundle.js |
| Самый медленный файл | Roboto Latin |
Как выглядит процесс загрузки
Когда пользователь открывает страницу:
1. Загружается HTML
2. Браузер находит CSS
3. Загружается CSS
4. Загружается JavaScript
5. Загружаются шрифты
6. Загружается индекс поиска
7. Инициализируется поиск
8. Страница готова
Упрощённая временная диаграмма:
0ms
├── HTML (64ms)
├── CSS (94ms)
├── Google Fonts CSS (36ms)
├── bundle.js (135ms)
├── Шрифты (91-194ms)
├── search_index.json (65ms)
├── search worker (70ms)
├── lunr stemmer (80ms)
└── lunr.ru (49ms)
440ms
Страница полностью загружена
Большинство ресурсов загружается параллельно благодаря HTTP/2 и HTTP/3.
Как работает поиск
Поиск полностью клиентский.
Никакого сервера для поиска нет.
Что участвует в поиске
Во время сборки создаётся файл:
search/search_index.json
В него попадают:
- заголовки;
- ссылки;
- текст статей.
Что происходит при поиске
Пользователь вводит запрос:
CRM
Дальше:
- Поисковый воркер получает запрос.
- Lunr.js разбивает текст на токены.
- Выполняется стемминг.
- Производится поиск по индексу.
- Результаты сортируются.
- Показываются пользователю.
Русский язык
Material использует расширение Lunr для русского языка.
Например:
маркетинг
маркетинга
маркетингу
Приводятся к общей основе.
Поэтому поиск работает корректно даже по склонениям.
Что занимает больше всего места
Если посмотреть на распределение ресурсов:
| Тип | Вес |
|---|---|
| Шрифты | ~110 KB |
| JavaScript | ~40 KB |
| Индекс поиска | ~28 KB |
| CSS | ~26 KB |
| Остальное | ~12 KB |
Самые тяжёлые ресурсы — вовсе не HTML.
Большую часть занимают шрифты Roboto.
Именно они являются главным ограничением по скорости загрузки.
Почему сайт работает быстро
Есть несколько причин.
Статика
Все страницы уже готовы заранее.
Ничего не генерируется на сервере.
GitHub Pages
Файлы раздаются через CDN GitHub.
Повторные посещения часто получают ресурсы из кеша.
Сжатие
HTML, CSS, JavaScript и JSON передаются в сжатом виде.
Минификация
CSS и JavaScript уже оптимизированы во время сборки.
Параллельная загрузка
Браузер не ждёт завершения одного запроса для начала следующего.
Итоги
После нескольких экспериментов с собственным генератором, шаблонами и альтернативными решениями я в итоге остановился на связке:
MkDocs
+
Material
+
GitHub Pages
На практике это дало:
- простую структуру проекта;
- обычные Markdown-файлы;
- встроенный поиск;
- автоматическую навигацию;
- адаптивный интерфейс;
- автоматическую публикацию через
gh-deploy; - полную загрузку сайта примерно за 440 мс.
Для проекта, который по сути является библиотекой текстов и заметок, этого оказалось более чем достаточно.
А главное — всё внимание можно тратить на контент, а не на поддержку собственного генератора сайтов.