Легковесная блог-платформа, написанная на Haskell с использованием веб-фреймворка Yesod. Использует Redis для кэширования данных и SQLite для сортировки данных.
Эта ветка не содержит каких-либо CSS для веб-страниц. Если вам нужна платформа с минимальным дизайном, посмотрите ветку main-bulma
.
- Полный Server-side Rendering! 🚀
- Посты хранятся в Markdown и YML файлах
- Автогенерация sitemap.xml
- Внутреннее кеширование в Redis
- Автогенерация ID заголовков
- Генерация OpenGraph и JSON-LD для страниц
- Генерация оглавления постов
- Опция для отключения автогенерации ID заголовков
Главная идея проекта - хранение постов блога в Markdown файлах с директории templates
.
В качестве URL страницы будут использованы имена директорий и файлов. Каждый пост состоит из двух файлов:
- Markdown файл, который содержит контент страницы, примерный файл
- YML файл, который включает в себя информацию о посте по типу заголовка, изображений, описания и прочего, пример.
Например, пост https://YOURSITE.HERE/post/haskell/how-to-start-yesod
будет храниться в файлах
./templates/haskell/how-to-start-yesod.md
и ./templates/haskell/how-to-start-yesod.yml
.
Парсинг Markdown реализован при помощи библиотеки Attoparsec
в модуле Parser
и теоретически может быть расширен. Сейчас реализованы базовые элементы Markdown, такие как:
- Заголовки
- Списки
- Блоки кода
- Цитаты
- Изображения
- Ссылки
- Форматирование текста (жирный текст и курсив)
Результат парсинга обоих файлов хранятся в Redis одну минуту. Это может быть изменено в модуле Redis.
К тому же, blog-hs хранит данные о постах в базе данных SQLite, которая используется для выборки последних постов на главной
странице и генерации файла sitemap.xml. База данных создается вручную при помощи команды create-db
и
хранит данные из YML файлов.
В данный момент функция недоступна для конфигурации. Каждый заголовок получает ID исходя из его содержания - изображения преобразуются в их альтеративный текст, форматирование текста игнорируется. Весь текст приводится к нижнему регистру и соединяется через тире вместо проблема. Знаки препинания игнорируются.
Рядом с каждым заголовком находится символ параграфа, по которому можно перейти.
Все детали описаны в модулях Parser/Inline.hs
и Parser/Html.hs
.
# Этот заголовок превратится в ID ниже
<h1 id="etot-zagolovok-prevratitsya-v-id-nizhe"> Этот заголовок превратится в ID ниже </h1>
Некоторые символы (как русский алфавит по умолчанию) транслитерируются в английский. Все символы
кроме указаных игнорируются. Для корректировки поведения изучите функцию transliterateCharacter
.
Информация о посте всегда хранится в .yml (не .yaml) файлах с тем же наименованием, что и пост и имеет следующие поля:
Поле | Тип | Описание |
---|---|---|
name | Строка | Заголовок поста |
description | Строка | Описание поста |
date | Строка | Дата поста в формате "YYYY-MM-DD" |
images | Список строк | URL изображений для превью в OpenGraph, JSON-LD и проч. |
Примерный файл - example.yml.
Для каждого поста могут быть указаны категории при помощи секции categories
. Она содержит список строк, которые
являются именами категорий. Используя категории, вы можете группировать посты и отображать их на отдельном экране.
Посты определенной категории отображаются на странице с URL /category/<имя категории>
. По умолчанию, выводятся 10 постов на страницу.
-
-f <ПУТЬ>
: указывает путь для конфигурационного файла -
-p <ПОРТ>
: указывает порт для сервера. Стандартный - 3000 -
-c
/--create-db
: создать базу данных SQLite при запуске командыrun
Blog-hs имеет следующие команды:
- check: проверяет наличие YML файлов для каждого в MD файла. Производит проверку в папке
templates
рабочей директории.
- create-db: создает (или заменяет) базу данных SQLite. И также производит валидацию файлов.
- run: запускает сервер.
Конфигурационный файл передается при помощи флага -f
. Иначе, сервер получит необходимые параметры из переменных окружения
или будет использовать стандартные значения.
Поле в конфиге | Имя переменной окружения | Описание | Стандартное значение |
---|---|---|---|
redisHost | REDIS_HOST | Адрес Redis | localhost |
redisPort | REDIS_PORT | Порт Redis сервера | 6379 |
dbPath | DB_PATH | Путь к базе данных SQLite | ./blog.db |
blogDepthLimit | DEPTH_LEVEL | Насколько "глубоко" в директориях можно уйти. Если запрос попытается пройти через слишком большое количество директорий, сервер вернет ошибку. | 1 |
siteName | SITE_NAME | Короткое описание сайта. Используется в OG и JSON-LD | - |
siteHost | SITE_HOST | Основная часть URL. Например, "https://mrtstg.ru". Без слеша в конце, используется для генерации ссылок. | - |
robotsFilePath | ROBOTS_TXT_PATH | Путь к файлу robots.txt. | - |
redisCacheTime | REDIS_CACHE_TIME | Время в секундах, на которое Redis будет хранить распарсеный пост | 60 |
Если необходимо, вы можете выключить ряд страниц, например главную или страницу категорий. В таком случае, используйте секцию
disabledPages
в конфигурационном файле. Она имеет тип списка строк, где значение:
index
это главная страницаcategory
/categories
это страница с постами определенных категорий. Также эта опция выключает генерацию ссылок на данную страницу на странице поста.robots
/robots.txt
- отдача robots.txt файлаsitemap
/sitemap.xml
- генерация файла sitemap.xml.
Также, вы можете использовать переменные окружения ENABLE_INDEX
и ENABLE_CATEGORIES
, которые принимают 1
как True и любое
другое значение как False.
Конфигурационный файл содержит секцию categories
. Она состоит из списка объектов следующего вида:
name: "имя-категории-для-URL-и-постов"
displayName: "Отображаемое имя на сайте"
description: "Описание категории"
В данный момент указать категории при помощи переменных окружения нельзя.
По умолчанию, веб-сервер отрисовывает в начале страницы заголовок поста, дату и категории. Это поведение
может быть изменено при помощи секции renderSettings
конфигурационного файла.
Эта секция имеет поля renderTitle
, renderDate
и renderCategories
,
которые управляют поведением. Если поле не указано, его значение True
по умолчанию.
Вы можете отключить отрисовку OpenGraph и JSON-LD информации при помощи поля renderMeta
.
renderSettings:
renderDate: false
renderTitle: true
renderMeta: false
# renderCategories: true по умолчанию
В качестве альтернативы запуска собранного бинарного файла есть вариант запуска контейнера Docker при помощи Docker Compose.
Если у вас установлен make
, вы можете сделать это при помощи:
make build-image # соберет образ контейнера
make deploy
Для уничтожения контейнеров, используйте команды make destroy
.
Этот метод по умолчанию подразумевает настройку через переменные окружения.
❗ Не забудьте откорректировать файл robots.txt! Он не генерируется автоматически.
Код распространяется под лицензией BSD 3 Clause. Обратите внимание на файл LICENSE.