Сравнение нюансов тем для двух основных генераторов статических сайтов JAMstack

Недавно я взял на себя задачу создать тему сайта документации для двух проектов. Оба проекта нуждались в одинаковых базовых функциях, но в одном используется Jekyll, а в другом - Hugo.

С точки зрения типичного разработчика, очевидно, был только один вариант. Я решил создать одну и ту же тему в обоих фреймворках и дать вам, дорогой читатель, параллельное сравнение.

Этот пост не является исчерпывающим руководством по созданию темы, а предназначен для ознакомления вас с процессом создания темы в любом из генераторов. Вот что мы расскажем:

1. How theme files are organized
2. Create a stylesheet
3. Sass and CSS in Jekyll
4. Sass and Hugo Pipes in Hugo
5. Configure and deploy to GitHub Pages
6. Configure Jekyll
7. Deploy to GitHub Pages

Вот дерьмовый каркас темы, которую я собираюсь создать.

Если вы планируете развивать тему, возможно, будет полезно обслуживать тему локально по мере ее создания; оба генератора предлагают эту функцию. Для Джекилла запустите jekyll serve, а для Хьюго запустите hugo serve.

Есть два основных элемента: основная область содержимого и важнейшее меню боковой панели. Для их создания вам потребуются файлы шаблонов, которые сообщают генератору сайта, как создавать HTML-страницу. Чтобы организовать файлы шаблонов тем разумным образом, вам сначала нужно знать, какую структуру каталогов ожидает генератор сайта.

Как организованы файлы тем

Jekyll поддерживает темы на основе гемов, которые пользователи могут устанавливать, как и любые другие драгоценные камни Ruby. Этот метод скрывает файлы тем в геме, поэтому для целей этого сравнения мы не используем темы на основе гемов.

Когда вы запустите jekyll new-theme <name>, Jekyll создаст для вас новую тему. Вот как выглядят эти файлы:

.
├── assets
├── Gemfile
├── _includes
├── _layouts
│   ├── default.html
│   ├── page.html
│   └── post.html
├── LICENSE.txt
├── README.md
├── _sass
└── <name>.gemspec

Имена каталогов достаточно информативны. Каталог _includes предназначен для небольших фрагментов кода, которые вы повторно используете в разных местах, почти так же, как вы смазываете все маслом. (Только я?) Каталог _layouts содержит шаблоны для разных типов страниц вашего сайта. Папка _sass предназначена для файлов Sass, используемых для создания таблицы стилей вашего сайта.

Вы можете создать новую тему Hugo, запустив hugo new theme <name>. В нем есть эти файлы:

.
├── archetypes
│   └── default.md
├── layouts
│   ├── 404.html
│   ├── _default
│   │   ├── baseof.html
│   │   ├── list.html
│   │   └── single.html
│   ├── index.html
│   └── partials
│       ├── footer.html
│       ├── header.html
│       └── head.html
├── LICENSE
├── static
│   ├── css
│   └── js
└── theme.toml

Вы можете увидеть некоторое сходство. Файлы шаблонов страниц Хьюго заправлены в layouts/. Обратите внимание, что у типа страницы _default есть файлы для list.html и single.html. В отличие от Jekyll, Hugo использует эти конкретные имена файлов, чтобы различать страницы со списком (например, страницу со ссылками на все ваши сообщения в блоге) и отдельные страницы (например, одну из ваших сообщений в блоге). Каталог layouts/partials/ содержит многоразовые биты, а для файлов таблиц стилей выделено место в static/css/.

Эти структуры каталогов не высечены в камне, поскольку оба генератора сайтов допускают некоторую настройку. Например, Jekyll позволяет вам определять коллекции, а Hugo использует пакеты страниц. Эти функции позволяют вам организовать ваш контент несколькими способами, но пока давайте посмотрим, где разместить несколько простых страниц.

Куда размещать контент

Чтобы создать меню сайта, которое выглядит так:

Introduction
    Getting Started
    Configuration
    Deploying
Advanced Usage
    All Configuration Settings
    Customizing
    Help and Support

Вам понадобятся два раздела («Введение» и «Расширенное использование»), содержащие соответствующие подразделы.

Jekyll не строго придерживается местоположения своего контента. Он ожидает страниц в корне вашего сайта и будет строить все, что там есть. Вот как вы можете организовать эти страницы в корне вашего сайта Jekyll:

.
├── 404.html
├── assets
├── Gemfile
├── _includes
├── index.markdown
├── intro
│   ├── config.md
│   ├── deploy.md
│   ├── index.md
│   └── quickstart.md
├── _layouts
│   ├── default.html
│   ├── page.html
│   └── post.html
├── LICENSE.txt
├── README.md
├── _sass
├── <name>.gemspec
└── usage
    ├── customizing.md
    ├── index.md
    ├── settings.md
    └── support.md

Вы можете изменить расположение источника сайта в своей Конфигурации Jekyll.

В Hugo весь отображаемый контент ожидается в папке content/. Это предотвращает попытки Hugo отображать нежелательные страницы, например 404.html, в качестве содержания сайта. Вот как можно организовать свой content/ каталог в Hugo:

.
├── _index.md
├── intro
│   ├── config.md
│   ├── deploy.md
│   ├── _index.md
│   └── quickstart.md
└── usage
    ├── customizing.md
    ├── _index.md
    ├── settings.md
    └── support.md

Для Хьюго _index.md и index.md означают разные вещи. Может быть полезно знать, какой тип пакета страниц вы хотите использовать для каждого раздела: лист, без дочерних элементов или ветвь.

Теперь, когда у вас есть представление о том, где разместить вещи, давайте посмотрим, как создать шаблон страницы.

Как работает шаблонизатор

Шаблоны страниц Jekyll созданы с использованием языка шаблонов Liquid. Он использует фигурные скобки для вывода переменного содержания на страницу, например заголовка страницы: {{ page.title }}.

В шаблонах Хьюго также используются фигурные скобки, но они созданы с помощью Go Templates. Синтаксис похож, но отличается: {{ .Title }}.

И шаблоны Liquid, и Go могут обрабатывать логику. Liquid использует синтаксис тегов для обозначения логических операций:

{% if user %}
  Hello {{ user.name }}!
{% endif %}

И Go Templates помещает свои функции и аргументы в синтаксис фигурных скобок:

Hello !

Языки шаблонов позволяют вам создать одну скелетную HTML-страницу, а затем указать генератору сайта разместить переменное содержимое в определенных вами областях. Давайте сравним два возможных default шаблона страниц для Джекилла и Хьюго.

Тема каркаса Jekyll default пуста, поэтому мы рассмотрим их стартовую тему Minima. Вот _layouts/default.html в Jekyll (Liquid):

<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: "en" }}">

  {%- include head.html -%}

  <body>

    {%- include header.html -%}

    <main class="page-content" aria-label="Content">
      <div class="wrapper">
        {{ content }}
      </div>
    </main>

    {%- include footer.html -%}

  </body>

</html>

Вот тема оформления Хьюго layouts/_default/baseof.html (шаблоны Go):

<!DOCTYPE html>
<html>
    
    <body>
        
        <div id="content">
        {{- block "main" . }}{{- end }}
        </div>
        
    </body>
</html>

Другой синтаксис, та же идея. Оба шаблона содержат многоразовые биты для head.html, header.html и footer.html. Они появляются на многих страницах, поэтому есть смысл не повторяться. В обоих шаблонах также есть место для основного контента, хотя в шаблоне Jekyll используется переменная ({{ content }}), а в Hugo - блок ({{- block "main" . }}{{- end }}). Блоки - это еще один способ, которым Hugo позволяет определять повторно используемые биты.

Теперь, когда вы знаете, как работает шаблон, вы можете создать меню боковой панели для темы.

Создание меню верхнего уровня с помощью объекта Pages

Вы можете программно создать меню верхнего уровня из своих страниц. Это будет выглядеть так:

Introduction
Advanced Usage

Начнем с Джекила. Вы можете отображать ссылки на страницы сайта в своем шаблоне Liquid, перебирая объект site.pages, который предоставляет Jekyll, и создавая список:

<ul>
    {% for page in site.pages %}
    <li><a href="{{ page.url | absolute_url }}">{{ page.title }}</a></li>
    {% endfor %}
</ul>

Это вернет все страницы сайта, включая все те, которые вам могут не понадобиться, например 404.html. Вы можете фильтровать страницы, которые вам действительно нужны, с помощью еще пары тегов, например, условно включая страницы, если для них установлен параметр section: true:

<ul>
    {% for page in site.pages %}
    {%- if page.section -%}
    <li><a href="{{ page.url | absolute_url }}">{{ page.title }}</a></li>
    {%- endif -%}
    {% endfor %}
</ul>

Вы можете добиться того же эффекта с немного меньшим количеством кода в Hugo. Прокрутите объект .Pages Хьюго, используя действие range в Go Template:

<ul>
{{ range .Pages }}
    <li>
        <a href=""></a>
    </li>
{{ end }}
</ul>

Этот шаблон использует объект .Pages для возврата всех страниц верхнего уровня в каталоге content/ вашего сайта Hugo. Поскольку Hugo использует определенную папку для контента сайта, который вы хотите отобразить, дополнительная фильтрация не требуется для создания простого меню страниц сайта.

Создание меню с вложенными ссылками из списка данных

Оба генератора сайтов могут использовать отдельно определенный список данных со ссылками для отображения меню в вашем шаблоне. Это больше подходит для создания вложенных ссылок, например:

Introduction
    Getting Started
    Configuration
    Deploying
Advanced Usage
    All Configuration Settings
    Customizing
    Help and Support

Jekyll поддерживает файлы данных в нескольких форматах, включая YAML. Вот определение меню выше в _data/menu.yml:

section:
  - page: Introduction
    url: /intro
    subsection:
      - page: Getting Started
        url: /intro/quickstart
      - page: Configuration
        url: /intro/config
      - page: Deploying
        url: /intro/deploy
  - page: Advanced Usage
    url: /usage
    subsection:
      - page: Customizing
        url: /usage/customizing
      - page: All Configuration Settings
        url: /usage/settings
      - page: Help and Support
        url: /usage/support

Вот как отобразить данные в шаблоне боковой панели:

{% for a in site.data.menu.section %}
<a href="{{ a.url }}">{{ a.page }}</a>
<ul>
    {% for b in a.subsection %}
    <li><a href="{{ b.url }}">{{ b.page }}</a></li>
    {% endfor %}
</ul>
{% endfor %}

Этот метод позволяет создать собственное меню с двумя уровнями вложенности. Уровни вложенности ограничены for циклами в шаблоне. Для рекурсивной версии, которая обрабатывает дополнительные уровни вложенности, см. Навигация по вложенному дереву с рекурсией.

Hugo делает нечто подобное со своими шаблонами меню. Вы можете определить ссылки меню в своей конфигурации сайта Hugo и даже добавить полезные свойства, которые понимает Hugo, например, взвешивание. Вот определение меню выше в config.yaml:

sectionPagesMenu: main

menu:  
  main:
    - identifier: intro
      name: Introduction
      url: /intro/
      weight: 1
    - name: Getting Started
      parent: intro
      url: /intro/quickstart/
      weight: 1
    - name: Configuration
      parent: intro
      url: /intro/config/
      weight: 2
    - name: Deploying
      parent: intro
      url: /intro/deploy/
      weight: 3
    - identifier: usage
      name: Advanced Usage
      url: /usage/
    - name: Customizing
      parent: usage
      url: /usage/customizing/
      weight: 2
    - name: All Configuration Settings
      parent: usage
      url: /usage/settings/
      weight: 1
    - name: Help and Support
      parent: usage
      url: /usage/support/
      weight: 3

Хьюго использует identifier, которое должно соответствовать имени раздела, вместе с переменной parent для обработки вложенности. Вот как отобразить меню в шаблоне боковой панели:

<ul>
    {{ range .Site.Menus.main }}
    {{ if .HasChildren }}
    <li>
        <a href="{{ .URL }}">{{ .Name }}</a>
    </li>
    <ul class="sub-menu">
        {{ range .Children }}
        <li>
            <a href="{{ .URL }}">{{ .Name }}</a>
        </li>
        {{ end }}
    </ul>
    {{ else }}
    <li>
        <a href="{{ .URL }}">{{ .Name }}</a>
    </li>
    {{ end }}
    {{ end }}
</ul>

Функция range выполняет итерацию по данным меню, а переменная Хьюго .Children обрабатывает вложенные страницы за вас.

Собираем шаблон вместе

С вашим меню в многоразовом бите боковой панели (_includes/sidebar.html для Jekyll и partials/sidebar.html для Hugo) вы можете добавить его в шаблон default.html.

В Джекилле:

<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: "en" }}">

{%- include head.html -%}

<body>
    {%- include sidebar.html -%}

    {%- include header.html -%}

    <div id="content" class="page-content" aria-label="Content">
        {{ content }}
    </div>

    {%- include footer.html -%}

</body>

</html>

В Хьюго:

<!DOCTYPE html>
<html>


<body>
    

    
    <div id="content" class="page-content" aria-label="Content">
        {{- block "main" . }}{{- end }}
    </div>
    
</body>

</html>

Когда сайт будет создан, каждая страница будет содержать весь код из вашего sidebar.html.

Создать таблицу стилей

Оба генератора сайтов принимают Sass для создания таблиц стилей CSS. Джекил имеет встроенную обработку Sass, а Хьюго использует Hugo Pipes. У обоих вариантов есть свои особенности.

Sass и CSS в Jekyll

Чтобы обработать файл Sass в Jekyll, создайте свои определения стилей в каталоге _sass - например, в файле по адресу _sass/style-definitions.scss:

$background-color: #eef !default;
$text-color: #111 !default;

body {
  background-color: $background-color;
  color: $text-color;
}

Jekyll не будет создавать этот файл напрямую, так как он обрабатывает файлы только с предварительной записью. Чтобы создать конечный путь к файлу для таблицы стилей вашего сайта, используйте заполнитель с пустым титульным листом там, где вы хотите разместить .css файл, например assets/css/style.scss. В этом файле просто импортируйте свои стили:

---
---

@import "style-definitions";

У этой довольно хакерской конфигурации есть положительный момент: вы можете использовать теги и переменные шаблона Liquid в своем файле-заполнителе. Это хороший способ разрешить пользователям устанавливать переменные, например, с сайта _config.yml.

Полученная таблица стилей CSS на вашем сгенерированном сайте имеет путь /assets/css/style.css. Вы можете разместить ссылку на него в head.html своего сайта, используя:

<link rel="stylesheet" href="{{ "/assets/css/style.css" | relative_url }}" media="screen">

Сасс и Хьюго Пайпс в Хьюго

Hugo использует Hugo Pipes для преобразования Sass в CSS. Вы можете добиться этого, используя функцию обработки ресурсов Хьюго, resources.ToCSS, которая ожидает источник в каталоге assets/. В качестве аргумента он принимает файл SCSS. Используя определения ваших стилей в файле Sass по адресу assets/sass/style.scss, вот как получить, обработать и связать ваш Sass в head.html вашей темы:

{{ $style := resources.Get "/sass/style.scss" | resources.ToCSS }}
<link rel="stylesheet" href="{{ $style.RelPermalink }}" media="screen">

Обработка активов Hugo требует расширенного Hugo, которого у вас может не быть по умолчанию. Вы можете получить расширенный Hugo на странице релизов.

Настроить и развернуть на страницах GitHub

Прежде чем ваш генератор сайтов сможет построить ваш сайт, ему нужен файл конфигурации для установки некоторых необходимых параметров. Файлы конфигурации находятся в корневом каталоге сайта. Среди других настроек вы можете объявить имя темы, которая будет использоваться при создании сайта.

Настроить Jekyll

Вот минимальный _config.yml для Джекилла:

title: Your awesome title
description: >- # this means to ignore newlines until "baseurl:"
  Write an awesome description for your new site here. You can edit this
  line in _config.yml. It will appear in your document head meta (for
  Google search results) and in your feed.xml site description.
baseurl: "" # the subpath of your site, e.g. /blog
url: "" # the base hostname & protocol for your site, e.g. http://example.com
theme: # for gem-based themes
remote_theme: # for themes hosted on GitHub, when used with GitHub Pages

С remote_theme любая тема Jekyll, размещенная на GitHub, может использоваться с сайтами, размещенными на страницах GitHub.

Jekyll имеет конфигурацию по умолчанию, поэтому любые параметры, добавленные в ваш файл конфигурации, переопределяют значения по умолчанию. Вот дополнительные настройки конфигурации.

Настроить Hugo

Вот минимальный пример config.yml Хьюго:

baseURL: https://example.com/ # The full domain your site will live at
languageCode: en-us
title: Hugo Docs Site
theme: # theme name

Хьюго не делает никаких предположений, поэтому, если необходимый параметр отсутствует, вы увидите предупреждение при создании или обслуживании своего сайта. Вот все настройки конфигурации для Hugo.

Развернуть на страницах GitHub

Оба генератора создают ваш сайт с помощью команды.

Для Джекила используйте jekyll build. Смотрите дополнительные варианты сборки здесь.

Для Хьюго используйте hugo. Вы можете запустить hugo help или просмотреть дополнительные параметры сборки здесь.

Вам нужно будет выбрать источник для вашего сайта GitHub Pages; после этого ваш сайт будет обновляться каждый раз, когда вы запускаете новую сборку. Конечно, вы также можете автоматизировать сборку GitHub Pages с помощью GitHub Actions. Вот один для сборки и развертывания с Hugo и один для сборки и развертывания Jekyll.

Время для шоу

Все существенные различия между этими двумя генераторами скрыты под капотом; Тем не менее, давайте посмотрим на готовые темы в двух цветовых вариациях.

Хьюго

Джекил

Шикарно!

Подожди, кто победил?

И у Хьюго, и у Джекила есть свои причуды и удобства.

С точки зрения разработчика, Jekyll - подходящий выбор для простых сайтов без сложных организационных требований. Если вы хотите рендерить некоторые одностраничные сообщения в доступной теме и размещать их на GitHub Pages, Jekyll поможет вам быстро приступить к работе.

Лично я использую Hugo. Мне нравятся организационные возможности его Page Bundles, и он поддерживается преданной и добросовестной командой, которая, кажется, действительно стремится облегчить удобство для своих пользователей. Это очевидно во многих функциях и удобных приемах Хьюго, таких как обработка магов и шорткоды. Кажется, они выпускают новые исправления и версии примерно так же часто, как я делаю новую чашку кофе, что, в зависимости от вашего варианта использования, может быть фантастическим или раздражающим.

Если вы все еще не можете решить, не волнуйтесь. Созданная мной Тема документации OpenGitDocs доступна как для Hugo, так и для Jekyll. Начните с одного, а при желании смените его позже. В этом преимущество выбора.