Эрзац-Hugo
Не раз мигрировал свой хобби-сайт на разные движки. Было несколько проектов на PHP, превращающихся в разные статические генераторы:
Потом брал специализированные генераторы:
- Jekyll - реализовал нужные функции успешно, но не устроил сложностью установки на новую машину. Он тащит за собой среду разработки для Ruby, ещё и устаревшей версии, которую устанавливать всё сложнее. В очередной раз установить вовсе не получилось.
- Hugo - одна из самых успешных реализаций. Быстро мигрировал сайт с Jekyll. В целом, всё устраивало, кроме необъяснимого размера репозитория: более 450МБ при реальном контенте максимум на 50. И всё меньше нравилось, что функций много, но управлять ими неудобно, а нужное вовсе не допишешь.
К Hugo приладил вспомогательный скрипт на Bash, причёсывающий сгенерированный результат. Собиралось это всё равно на локальной машине и загружалось на удалённый сервер через Git. Подумал, почему бы не заменить Hugo на свою реализацию полностью на Bash, ведь там всё просто: перебирай себе файлы, преобразуя Makdown в HTML, оборачивая в шаблон.
Первым этапом так было и сделано. Система шаблонов получилось даже удобнее, чем у Hugo, как и управление разделами: теперь это просто контент в папках без каких либо настроек и служебных файлов. Индексные файлы наполнялись ссылками на все остальные файлы из их папок.
Переменные контента (заголовок, дата, описание и другие) хранятся в формате Yaml, как у Hugo. Парсера Yaml как такового нет: файл считывается построчно и всё между первым и вторым ---
считается за список переменных вида ключ: значение
.
Следующим этапом добавлена генерация страниц тегов. Ещё во время первого прохода собирался список ссылок: к какому тегу какие статьи относятся. Потом всё это записывается в одноимённые файлы /tags/*.html.
Там же собирался общий список всех страниц, который ближе к концу скрипта преобразуется в sitemap. И на сдачу, генерируется страница 404 на основе базового шаблона.
Как основа ссылок используются пути до файлов без .html, которые перезаписываются через .htaccess, как и на других генераторах. Сначала контент записывался в name.html
файлы, в последний момент передалал на структуру name/index.html
, как было в Hugo для упрощения просмотра с локальной машины. Внешний результат получился такой же, как у Hugo.
Hugo и Jekyll поставляют свой вебсервер с горячей перезагрузкой контента. Финальный билд делается для загрузки на внешний сервер. В моей версии, понятно, никакого сервера нет - это только генератор. Все ссылки обычно идут от корня /, поэтому для просмотра нужен локальный вебсервер. Можно использовать микровебсервер python3 -m http.server 8000
или другой. Для предпросмотра придётся собрать полный билд.
Скрипт вышел немного запутанный, т.к. Bash знаю плохо и активно пользовался ChatGPT, но совсем без понимания ничего бы реализовать не получилось.
Полные возможности скрипта build.sh:
- Поддержка Markdown и HTML как основных файлов контента.
- Все остальные файлы переносятся без изменений.
- Полная поддержка любой вложенности контента.
- Папка static, которая никак не обрабатывается.
- Автоматически генерируются индексные файлы.
- Карта сайта.
- Страница 404.
- Полная очистка _build-директории. У Hugo в аналогичной public копился мусор из удалённых в исходниках файлов.
Есть зависимость от большого стороннего пакета pandoc для обработки Markdown и необязательного пакета tidy для форматирования результата. Парсер pandoc немного отличается от Hugo и пришлось перебрать контент. В частности, pandoc требует отбивку списков пустыми строками. Я часто не отбивал список от параграфа. Ещё он добавляет теги p
внутрь li
, что пришлось визуально скорректировать через CSS.
- Работает на Linux при установке пакетов
apt-get install pandoc tidy
. - На MacOS нужно установить пакеты
brew install grep sed awk pandoc tidy-html5
- На Windows WSL2 нужно установить пакеты
apt-get install grep sed awk pandoc tidy
Время сборки зависит от контента. На сотне записей и 50МБ статических файлов работает около пяти секунд. Половину из этого занимает pandoc. Дополнительно исследовал другие парсеры Markdown. Скорость сравнивается относительно pandoc.
- cmark - 3 сек - самый быстрый, но некорректно кодирует кириллические ссылки, из-за чего не работает часть переходов по хешам. Хеши сам по себе не делает, но их можно добавить через JavaScript одной строкой.
- discount - 3 сек - скорость работы как у cmark, те же проблемы.
- markdown - 4 сек - немного медленнее, хеши не делает, кодировка ссылок правильная.
- grip - 19 сек - невероятно долгий, в разы медленней, ломает контент.
- python3 markdown2 - 6 сек - немного медленнее, хеши не ставит.
- python3 rst2html - 7 сек - медленней, ломает контент.
Итого можно оставить pandoc для полного функционала или markdown с расстановкой хешей через JS.
UP: позже дописал скрипт watch.sh, который предоставляет как бы автоматическую систему сборки с автозапуском сервера разработки. Всё ещё без hot reload, но это может быть реализовано плагинами браузера (не проверял).