Jekyll — генератор статических сайтов. Это означает, что на вход ему даётся какая-либо информация, а на выходе получается набор HTML-страничек. Всё отлично когда сайт простой или даже одностраничный. Но что насчёт более сложных сайтов? Справится ли Jekyll? Будет ли удобно? Данная публикация — попытка обобщить знания, полученные при создании нескольких веб-сайтов. Поэтому оставляю ссылки и на рабочие примеры, и на их полные исходники на GitHub. Уровень материала идёт от простого к сложному.  На хабре уже было несколько публикаций по Jekyll: Практическое руководство по Jekyll, Блог на Jekyll и Github, Jekyll 2 надвигается на Github!. Однако все они описывают в основном базовые возможности Jekyll. Кроме того, на GitHub Pages уже используется Jekyll 3, что привнесло новых плюшек. Итак, начнём! Сервис Github Pages использует Jekyll как генератор сайтов. Может ли GitHub Pages использован самостоятельно, без Jekyll? Да! Можно использовать GitHub Pages как простой HTML-хостинг (бесплатно!). Особенно, если сайт уже был где-то сгенерирован.  Например, Веб-демо Winter Novel было сгенерировано в С-приложении. Это просто пачка простых HTML-страниц, расположенных на GitHub Pages. Исходники здесь. Как было видно выше, существует возможность использовать своё доменное имя вместо *.github.io. И сделать это достаточно просто: нужно создать файл CNAME с единственной строкой — доменом: После коммита установленный домен так же можно видеть в настройках репозитория:  Можно использовать домены любого уровня, а не только третьего. Например, dexp.in тоже хостится на GitHub'e. Другой отличный бесплатный сервис — CloudFlare. Ведь в любом случае нужен менеджер DNS для домена. А CloudFlare предоставляет не только инструменты для управления DNS, но и CDN-сервис. Это значит, что CloudFlare может кэшировать страницы и отображать их даже если GitHub Pages будет недоступен.  Главный домен напрямую по IP привязан к GitHub. Субдомены реализованы через cname-альясы на dexp.github.io. Jekyll поддерживает и HTML и Markdown. HTML даёт больше возможностей, но не слишком удобен для написания человеком. Markdown — очень крутая штука для написания текстов. Пример куска текста на HTML: Как минимум, нужно добавлять и <p> и </p>… И пример куска текста на Markdown:  Markdown-код выглядит намного лучше. Просто попробуйте, не пожалеете. Sass — это язык поверх CSS. Добавлено много хорошей функциональности: переменные, блоки кода, вложенные правила, include и т.д. Пример SCSS кода с примесями и переменными: Код будет транслирован в: Полезные ссылки: Sass Basics, Sass Tutorial Ok, чистый HTML это уже хорошо. Но может в Jekyll есть что-то типа include? Тогда можно будет построить свои страницы в стиле: Да, в Jekyll есть include. Но лучше использовать эту директиву для других целей. Для внешнего вида же лучше использовать шаблоны: Layout. Пускай исходный код страницы выглядит следующим образом: И файл _layouts/default.html: Страница генерирует какой-то код и сохраняет его в переменную content. Jekyll из заголовка видит, что следующим обрабатываемым файлом будет _layouts/default.html. Далее нужно просто вывести содержимое этой переменной в любом месте кода. Конечно, в реальности код получается более сложным. Например, главная страница One Manga Day и layout для неё. Мы уже затронули тему переменных. Рассмотрим более подробно заголовок главной страницы One Manga Day: Переменная layout говорит Jekyll, какой следующий файл будет обрабатываться. Остальные переменные используются в коде layout и созданы для удобства:  Переменная page.title установлена в заголовке страницы, site.name — в _config.yml. Результатом выполнения этой строки в моём случае будет: One Manga Day | Home page Предыдущие возможности Jekyll были не очень продвинутыми, даже скорее базовыми. Но коллекции позволяют делать по-настоящему мощные вещи. Например, галереи. И как частный пример — страница с мангой.  Небольшая вырезка из _data/galleries.yml: В этом коде создаётся коллекция site.data.galleries. Первый знак минуса обозначает создание элемента коллекции. images — субколлекция, каждый элемент который имеет поля name, thumb и text. И пример, как работать с данной коллекцией, _includes/mangascript.html: Изначально коллекция site.data.galleries фильтруется по полю id (значение должно быть равно page.gId). Результатом фильтра where может быть несколько значений, поэтому берётся только первое (это позволительно, т.к. id коллекции в данном случае подразумевается уникальным). Результат сохраняется в переменную gallery. Далее просто проходим всю галерею в цикле for. Результат исполнения будет примерно таким: Полезные ссылки: Jekyll (Liquid) reference, "Advanced Liquid: Where". Ещё одно хорошая возможность для галерей — встраивание их коллекций прямо в код страницы. Например, страница игры: В эту страницу встроены сразу две коллекции: gallery и buttons. Переменные page.gallery и page.buttons используются в _includes/gallery и _includes/buttons соответственно.  Этот метод хорошо подходит, если нужно отобразить какую-то информацию, специфичную только для данной страницы. Если же коллекции используются во всём сайте (контакты/меню и т.п.), то лучше пользоваться предыдущим методом и хранить коллекции в каталоге _data. Мы уже затронули тему фильтров. Теперь можно взять и более продвинутую задачу. Я хочу увидеть все мои "Linux" посты, сгруппированные по году, только за 3 года. Сначала нужно взять все посты по тэгу "Linux": site.tags.linux. Следующая строка группирует по дате. Можно выбрать любое поле или формат для группировки. Ну и последнее условие выполняется через limit у цикла for. Вывод:  Реально это используется у меня в фотоальбоме (исходник). Пускай нужно не выводить сразу переменную {{ content }}, а как-либо её модифицировать, а только потом вывести.  Обычное присвоение: Не работает, т.к. нужны не сырые (raw) строки, а предобработанные с помощью Jekyll. Решением является директива capture. И для примера будет рассмотрен хак для обхода бага в compress.html. Пускай изначальный код выглядит следующим образом: Изменим его для использования capture: Теперь весь подсвеченный код находится в переменной _code. Далее происходит его обработка в _include/fixlinenos.html: Код проверяет на вхождение подстроки <pre class="lineno">. Если такая найдена, то у нас в наличии бажный HTML-код, неправильные куски которого просто заменяются на правильные. Полезная ссылка:  Jekyll (Liquid) string filters Можно ужать весь SASS-код всего одной строкой в _config.yml: Если нужно ужать SASS-код на лету, то можно воспользоваться фильтром scssify (стиль сжатия из конфига будет применён и для фильтра): В Jekyll не предусмотрено стандартных методов для сжатия HTML. Можно воспользоваться сторонним решением — compress.html. Нужно добавить всего одну строку в свой layout верхнего уровня: Компрессия будет происходить уже после всей генерации кода. В конечном счёте HTML-код страницы будет выглядеть примерно так:  Пускай нужно подсветить синтаксис какого-нибудь экзотического языка программирования, о котором не знает Jekyll. Это можно сделать программно. Я сделал customhighlight.html для подсветки RenPy кода (базируется на Python). Идея проста и тоже базируется на фильтре replace: Здесь формируется массив тэгов, потом поиск-замена для каждого элемента в строке кода. Единственная новая вещь — это разделение строки в массив. Пример подсвеченного кода:  Пример использования здесь. Также подсветка встроена в код оригинальной статьи на английском. Облако тэгов — ещё более сложная задача. Во-первых, для каждого тэга вручную должна быть создана своя страница. Во-вторых, нужно сделать массив валидных тэгов с их человеко-читаемыми именами. В-третьих, скрипт должен подсчитать количество статей для каждого тэга.  Основные вычисления происходят в файле _includes/tagcloud.html: Переменная site.tags хранит все использованные тэги из всех статей. Переменная langtag — это текущий тэг в человеческом формате, описанный в _data/lang.yml. На каждой итерации будет переменная tag, взятая из коллекции site.tags. Переменная tag содержит список всех статей с данным тэгом. Так что можно просто взять размер, умножить, поделить и пр. Самый маленький тэг был слишком маленьким для меня, так что я добавил ещё 20%. Полезная ссылка:  Jekyll (Liquid) array filters Jekyll сам по себе не поддерживает интернационализацию. Так что придётся и это реализовывать самостоятельно. Самый простой метод — просто изолировать материалы по категории (например, материалы на русском). Также можно использовать поддомен для каждого языка. Но в таком случае для 2 языков будет существовать ровно 2 сайта. И 10 сайтов для 10 языков, что не всегда удобно.  На сайте One Manga Day для каждого языка выделена своя папка. Идея проста. Например, существует английская страница cat/page.html. Если у этой страницы есть русский вариант, то URL у неё будет ru/cat/page.html. Если страниц немного, то можно все их создавать вручную. Но если страниц много, то необходимо проверять наличие страницы на том или ином языке. Однако в Jekyll вообще не существует файловых функций в целях безопасности серверов GitHub. Для проверки существования файлов можно воспользоваться моим _includes/CHECKEXISTS.html. Там просто пробегаются все страницы и посты сайты: Если файл на языке существует, то можно добавлять ссылку на него на своей странице. Первое приходящее на ум решение — Disqus или подобная система комментариев на базе AJAX. В страницу просто встраивается небольшой JS-код и всё работает хорошо.  Но лично мне гораздо больше понравился Staticman — система комментариев, основанная на пулл-реквестах в репозиторий сайта. Таким образом комментарии также являются Jekyll-коллекцией!  Код для отображения комментариев к странице: Форма отправки комментария также достаточно проста:  Модерирование комментариев реализовано через подтверждение пулл-реквеста. Также можно просто попросить Staticman класть комментарии напрямую, минуя подтверждение реквеста. После принятия реквеста весь сайт будет перегенерирован и комментарий появится на сайте. Jekyll — очень крутая штука для маленьких сайтов и блогов. Просто попробуйте, вы его полюбите!  Программист