
Umzug von Jekyll zu Hugo
Inhalt
Projekt-Steckbrief#
- Schwierigkeitsgrad: Mittel 3/5
- Kosten: 0€
- Zeit ~20h
In diesem Projekt beschreibe ich meinen Umzug von Jekyll mit der Optik von Minimal Mistakes zu Hugo in einem stark modifizierten Terminal-Theme.
Warum überhaupt wechseln?#
Schon seit langem war ich nicht mehr vollständig zufrieden mit dem Bauen meiner Website per Jekyll. Der Auslöser für den Umstieg war, dass ich eines Tages plötzlich wegen eines Kompatibilitätsproblemes nicht mehr lokal bauen konnte. Ein bundle update --conservative oder bundle install wie üblich half nicht. Auch das manuelle Nachinstallieren der verursachenden Pakete per gem install commonmarker-0.23.12 oder gem install posix-spawn -v 0.3.15 -- --with-cflags=\"-Wno-incompatible-function-pointer-types\" brachten keine Abhilfe.

Ein Update von Ruby und Jekyll selbst brachte ebenfalls keinen Erfolg. Und überhaupt: Die Bauzeit mit Jekyll ist inzwischen ziemlich lang geworden. Ich bin durch meinen Umzug der Seite von Github Pages auf einen eigenen Server nicht mehr an Jekyll gebunden, was einen Wechsel attraktiver macht.
Weitere Schwierigkeiten mit Jekyll#
- CI/CD: Meine Deploy-Pipeline war vor Monaten mit ähnlichen Fehlern ausgefallen, sodass ich auf eine ältere Jekyll-Version zurückgreifen musste. Damit vergrößert sich technische Schuld und Angriffsfläche meiner Actions. Ich müsste auf die Suche nach einer gut gewarteten Containerlösung eines anderen Anbieters wechseln. Suche und Einrichtung würden zusätzliche Zeit erfordern.
- RSS-Feed: Ich möchte zu meiner Website gern einen RSS-Feed bereitstellen. Meine Experimente mit Jekyll zeigten jedoch, dass nur “Posts” und keine “Announcements” inkludiert werden. Das wollte ich beheben.
- Bildformate: Cover-Bilder (Thumbnails) für Posts werden im RSS-Feed durch Jekyll eigentlich mit gebaut. Durch meinen Umstieg von
.jpgauf das platzsparendere.aviffunktionierte das nun leider nicht mehr. Eine Lösung habe ich trotz mehrerer Anläufe nicht durch den Pull Request Review bekommen. - Icons: Das von mir verwendete Theme nutzt Font Awesome zur Darstellung von Icons und ist insgesamt für eine statische Website recht groß. Ich wollte aber nichts aus dem Netz nachladen und habe die Bibliothek daher lokal gespeichert. Daher war mein Plan, nur die wirklich benötigten Icons heraussuchen und den Rest zu löschen. Mit dem Umstieg auf Hugo ist dies nicht mehr notwendig.
Die Chancen#
Von Hugo verspreche ich mir schnellere Bauzeiten, eine vereinfachte CI/CD ohne Nachinstallieren von Bundler, Ruby etc. und die Behebung der oben beschriebenen Schwierigkeiten. Das Abhängigkeits- und Paketmanagement von Hugo unterscheidet sich grundlegend von Jekyll: Zusätzliche Inhalte werden per Git Submodules eingebunden und das Abhängigkeismanagement nutzt statt der Gemfile schlicht Go modules.
Das Migrationswerkzeug#
Die Ordnerstrukturen der Inhalte unterscheidet sich deutlich zwischen Jekyll und Hugo. Ich nutze daher ein in Hugo enthaltenes Importwerkzeug, welches mir zumindest die Artikel unter /posts korrekt importiert.
Alle spezifischen Inhalte wie Übersichtsseiten /tags, /pages/error, /pages/legal und Seiten, wo Projekte und Ankündigungen abgelegt sind /_announcements, /_projects, werden allerdings nicht mit umgezogen und müssen manuell kopiert und modifiziert werden.
Anpassen der Front Matter#
Viele von mir gemachten Anpassungen in Jekyll funktionieren in Hugo entweder nicht richtig oder führen zum Abbruch des Bauvorganges - die Front Matter einer jeden Markdown-Datei muss also angepasst und teils bereinigt werden.
---
# Alt: So kann die Front matter einer Übersichtsseite in Jekyll aussehen
lang: de
title: Beitragsarchiv
subtitle: Diese Sammlung enthält alle meine Beiträge
layout: collection
collection: posts
permalink: /posts-archive/
entries_layout: grid
classes: wide
author_profile: false
---
In meinem Falle liegen einige Theme-abhänigen Parameter im Frontmatter vor wie layout, classes, author_profile. Der lang-Parameter aus meiner Internationalisierungserweiterung in Jekyll ist nicht einmal korrekte Hugo-Syntax: es erwartet die angezeigte Sprache entweder als Feld unter params: lang oder Ordnerweit. Auch andere, an den eigenen Geschmack angepasste Parameter können definiert und unter params mitgegeben werden.
Permalinks finden gar keinen Eingang mehr in die Front matter, stattdessen findet die Konfiguration zentral statt.
Eine Hugo-kompatible front matter kann so aussehen:
---
title: Beitragsarchiv
description: Diese Sammlung enthält alle meine Beiträge
layout: collection
---
Konfiguration des Theme#
Eine Basis-Konfiguration meines Themes kann ich mit folgendem Kommando installieren:
➜ blog git:(main) ✗ git submodule add https://github.com/panr/hugo-theme-terminal ./themes/terminal
Zum Aktivieren muss ich es in der Hauptkonfiguration bekannt machen:
# /hugo.toml
# Add it only if you keep the theme in the `themes` directory.
# Remove it if you use the theme as a remote Hugo Module.
theme = "terminal"
Und schon baut Hugo für mich im Terminal-Theme und Originalfarben.

Dies ist nun nicht vertikal zentriert und für meinen Geschmack zu schmal ausgelegt, der Text recht klein und “meine” Blog-Farben sollen ebenfalls anders sein .
Daher erstelle ich eine .css-Datei, die einige Eigenschaften des Basis-Themes überschreibt. Sie muss im Ordner /static liegen und den Namen des Themes tragen.
/* /static/terminal.css */
:root{
--background: #252a34;
--background-highlight: #475064;
--foreground: #d2eaef;
--foreground-dimmed: #8b9ea2;
--accent: #25a679;
--accent-highlight: #79ae9c;
--radius: 8px;
--font-size: 1.35rem;
--line-height: 1.8em;
}
/* Use system fonts, reduce transferred kB */
body{
font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif !important;
}
/* make content wider */
body .container{
max-width: 70rem;
width: 90%;
}
Und schon sieht es fast wie früher aus.

Organisation der Ordnerstruktur#
Anders als bei der von mir verwendeten Jekyll-Version verfügt hugo über eingebaute Internationalisierung (i18n). Dafür muss ich meine Ordnerstruktur umbauen und explizit in /de und /en-Ordnerinhalte sortieren. Inhalte werden nun statt auf der höheren Ordner-Ebene direkt unter /_pages, /_announcements, /_posts im Ordner content gehalten, was die Sache übersichtlicher macht.
Vorher#
.
├── _announcements
├── assets
│ ├── css
│ │ ├── fontawesome
│ │ ├── katex
│ │ ├── main.scss # <-- theme import, customization
│ │ └── webfonts
│ ├── js
│ │ ├── lunr
│ │ ├── _main.js
│ │ ├── main.min.js
│ │ ├── plugins
│ │ └── vendor
│ └── video
├── banner.js
├── CNAME
├── _config.yml
├── _data
│ ├── de
│ │ ├── l10n.yml
│ └── en
│ ├── l10n.yml
├── en
│ └── index.html
├── Gemfile
├── Gemfile.lock
├── _includes # <-- Layouts (HTML), partials, 3rd-party
├── index.html # <-- Landing page
├── _layouts # <-- Page layouts
├── _pages
│ ├── 404.md # <-- German version
│ ├── [...]
│ ├── en
│ │ ├── 404.md # <-- English version
│ │ ├── [...]
├── _posts/
│ └── en
├── _projects/
├── _sass
│ ├── minimal-mistakes # <-- Styles (SCSS) for layouts and partials
│ ├── minimal-mistakes.scss
│ └── _video.scss
├── _site/ # <-- Build artifacts
├── staticman.yml
Nachher#
Einen guten Überblick über die Ordnerstruktur bietet Hugos Dokumentation. Am wichtigsten für die tägliche Arbeit mit Artikeln und Aussehen der Website sind die Stammordner content, layouts und static.
.
├── archetypes
├── assets
├── content
│ ├── de
│ │ ├── about.md
│ │ ├── announcements/
│ │ ├── posts/
│ │ └── projects/
│ └── en
│ ├── about.md
│ ├── [...]
├── data
├── hugo.yml
├── layouts
│ ├── _default
│ │ ├── baseof.html # <-- defines header, add-ons, content, footer structure
│ │ ├── index.html # <-- landing page
│ │ ├── list.html # <-- grid view
│ │ └── single.html # <-- post view
│ ├── _markup
│ │ └── render-link.html # <-- link highlighting and function (referrer, tabs)
│ ├── _partials
│ │ ├── cover.html # <-- cover (thumbnail) image rendering
│ │ └── math.html # <-- math rendering (katex)
│ └── _shortcodes
│ ├── audio.html
│ ├── image.html
│ └── [...]
├── resources
│ └── _gen
│ └── assets/
├── static
│ ├── assets
│ │ ├── audio/
│ │ ├── css/ # <-- contains overrides for custom layouts
│ │ ├── docs/
│ │ ├── images/
│ │ ├── js/ # <-- math (katex) JS lives here
│ │ └── video/
│ └── terminal.css # <-- Central theme override (colors, formatting, styling)
└── themes
└── terminal # <-- GIT submodule: Vanilla "Terminal" theme
Bei beiden Lösungen werden Layouts in html und Stil/Format ind CSS definiert. Da ich bei Jekyll mehr Plugins verwenden musste, wird das Setup größer.
Manuelle Anpassungen: Shortcodes#
Mit Shortcodes kann man in Hugo nicht-Text-Inhalte (Medien, Links, Formatierung, Stil) definieren, die dann nach definierter Vorschrift gerendert werden. Dafür legt man eine html-Datei an, welche den Dekorator definiert und entsprechende css-Klassen einbindet. Außerdem fügt man die gewünschte Formatierung in der überschreibenden Theme-css-Datei ein.
Da ich hier absolut kein Profi bin, probiere ich anschließend so lange herum, bis mir das Layouting gefällt und ich keine Artefakte/Überlagerungen mehr sehe.
.
├── layouts
│ └── _shortcodes
│ └── my-shortcode.html # <-- Custom shortcode file
├── static
│ └── terminal.css # <-- Central theme override (colors, formatting, styling)
Syntax: Hugo und Jekyll#
Shortcodes werden bei Hugo in der Markdown-Datei mit folgender Syntax angezeigt:
{{< shortcode-html-filename options >}}
{{< image src="/path/to/image.avif" alt="Image: alt text" position="right" >}}
Im Vergleich dazu sehen Shortcode-ähnliche Dekoratoren in Jekyll für Liquid, die in Jekyll benutzte Beschreibungssprache so aus:
### Liquid in interpreter code
{% Liquid bracket syntax %}
### Liquid "shortcode" pendant
{% include gallery id="gallery" caption="Eindrücke von **MobFobAmp**. Zum Vergrößern anklicken." %}
### Liquid decorator for layouting
{:.list-inline}
image#
Anwendungsbeispiel zur Bildanzeige. In der nächsten Zeile folgt ein zentriertes Bild.

Der klassische Bild-Dekorator für Markdown [Alt Text](/path/to/image) wird in Hugo standardmäßig als mittig zentriertes Bild ohne Textfluss gerendert. Für ein schönes Layouting benötige ich jedoch ein paar Varianten, welche etwas zusätzlichen Code in cascading style sheets und html erfordern.

- Bild zentriert, ohne Textfluss
- Bild links , Textfluss rechts
- Bild rechts, Textfluss links
Zuerst besorgt sich Hugo Dateipfad und Bildtext. Anschließend liest es die gewünschte Formatierung aus der Markdown-Datei, welche mit der position-Variable angelegt wird. Anschließend wendet sie die image-wrapper Klasse aus der .css-Datei darauf an. Die Ausrichtung der Bilder gilt für bessere Lesbarkeit nur für die Desktop-Variante der Webseite (>684px).
Die Anpassungen des Themes gehen zur richtigen Darstellung von Bildern recht weit. Außerdem habe ich noch eine Galerie entwickelt, falls ein Post über sehr viele Bilder verfügt. Daher habe ich für die Bildformatierung und -Ausrichtung einen eigenen Artikel geschrieben.
audio#
Zur Darstellung des Audio-Players verwende ich die im Browser implementierten Standards.
{{- /* /layouts/_shortcodes/audio.html */ -}}
{{ $src := .Get "src" }}
{{ $caption := .Get "caption" | default "" }}
<div class="media-wrapper">
<div class="media-container">
<audio controls>
<source src="{{ $src }}" type="audio/mp3">
Your browser does not support the audio element.
</audio>
{{ with $caption }}
<div class="media-title">{{ . }}</div>
{{ end }}
</div>
</div>
In css verwende ich einen Wrapper und Media-Container, um Titel im Rahmen des Players anzeigen zu können und die Formatierung zu erleichtern. Auch hier habe ich angepasstes Verhalten für ein “responsive layout” bei Mobilgeräten oder Änderungen der Größe des Browser-Fensters.
video#
Das CSS ist identisch mit audio. Es gibt nur im html geringfügige Unterschiede. Der von mir verwendete Container unterstützt unter src= als Quellen sowohl “embed-Links” von Webseiten wie peertube als auch lokale Quelldateien.
{{- /* /layouts/_shortcodes/video.html */ -}}
{{- $src := .Get "src" -}}
{{- $title := .Get "title" | default "" -}}
{{- $caption := .Get "caption" | default "" -}}
<div class="media-wrapper">
<div class="media-container">
{{- if hasPrefix $src "http" -}}
<iframe src="{{ $src }}" frameborder="0" allowfullscreen></iframe>
{{- else -}}
<video controls>
<source src="{{ $src }}" type="video/mp4">
Your browser does not support the video tag.
</video>
{{- end -}}
{{- if or $title $caption -}}
<div class="media-title">
{{- if $title -}}{{ $title }}{{- else -}}{{ $caption }}{{- end -}}
</div>
{{- end -}}
</div>
</div>
Updates#
Auch bei mir “altern” Inhalte. Manchmal wechsle ich Technologien oder Anbieter, und manchmal bewegen sich auch Dritte von Lösungen weg, deren Implementierung ich hier im Blog beschrieben habe. Daher habe ich update-shortcodes eingeführt.
Verlinkungen#
Folgendes Verhalten wünsche ich mir für Links auf meinem Blog:
- interne Links sollen im selben Tab geöffnet werden und die Nutzer weiterleiten.
- interne Links sollen zu Seiten in derselben Sprache verweisen und nicht auf die Standard-Sprache oder zurück zur Hauptseite führen.
- externe Links sollen mit einem Symbol gekennzeichnet werden:
↗ - externe Links sollen in einem frischen Tab geöffnet werden:
target="_blank" - exterme Links sollen weder auf die ursprünglichen Inhalte zugreifen noch den Quellverweis sehen können
rel="noopener noreferrer"
Dafür erstelle ich unter /layouts/_markup die Datei render-link.html.
Den Code hierfür und seine Hintergründe stelle ich in einem separaten Post vor: Hugo Multi-language: Interne Permalinks
Der Override für CSS sieht wie folgt aus.
/* /static/terminal.css */
.external-link .external-link-icon{
display: inline-block;
font-size: var(--font-size);
vertical-align: middle;
transform: translateY(-0.1em);
}
Manuelle Anpassungen: Partials#
Partials kann man sich vorstellen wie die Layout-Bausteine für eine Hugo-Website. Sie werden unter /layouts/_partials abgelegt und überschreiben die Standards des verwendeten Themes. Dabei wird die Ursprungsdatei gar nicht mehr geladen, was ein Herüberkopieren der Originaldatei in den Ordner mit anschließender manueller Anpassung empfehlenswert macht.
index#
Die Startseite für den Blog ist komplett selbt geschrieben und liegt nicht in Markdown, sondern in html vor. Sie zeigt ihre Inhalte anders an als alle anderen Blog-Seiten und daher lohnte es sich für mich nicht, Templates zu programmieren. In der entsprechenden /layouts/_partials/index.html lade ich dafür notwendige scss und css-Dateien und gebe die Struktur der Seite vor. Die folgende Tabelle gibt einen Überblick über meine Änderungen.
| File | Purpose | Customization |
|---|---|---|
| cover | thumbnail / cover image for overview pages, lists, and grids | Add custom cover image decorator, alt text |
| head | Defines Favicon, search console, page parameters, feeds etc. | Custom favicon path |
| header | Page header containing menu, logo, navigation etc. | Add logo and subtitle to menu, lang selector |
| logo | Custom page logo, title, subtitle | Full |
| math | Displays math content with Latex/Katex | None, implement math support |
math#
Mein Blog soll mathematische Notation unterstützen. Dafür benutze ich Katex
{{- /* /layouts/_partials/math.html */ -}}
<link rel="stylesheet" href="/assets/css/katex.min.css">
<script defer src="/assets/js/katex.min.js"></script>
<script defer src="/assets/js/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
delimiters: [
{left: '\\[', right: '\\]', display: true}, // block
{left: '$$', right: '$$', display: true}, // block
{left: '\\(', right: '\\)', display: false}, // inline
],
throwOnError : false
});
});
</script>
cover image#
Unter der Bezeichnung cover verstehe ich ein Titelbild eines Blog-Posts. Es wird in Übersichtsseiten, Artikel- und Tag-Listen etc. angezeigt und soll die Inhalte des Blog-posts unterstützend beschreiben. Auch mein RSS-Feed soll diese Bilder für die Übersicht verschiedener Artikel auf Endgeräten meiner Leserschaft verwenden.
Es ist besonders stark komprimiert und benötigt wenig Übertragungsbandbreite. Daher ist seine Auflösung gering (440x220 oder 640x352). Für einen einheitlichen Look sind sie zudem stets monochrom.
Die Markdown-Syntax zum Einbinden des Covers sehe ich wie folgt vor:
---
cover_alt: 'Image: Hugo console build output. It shows a full build time below 2sec. (~90% reduction over build time with Jekyll)'
cover: /assets/images/migrating-hugo-to-jekyll/hugo-jekyll-build-compare-cover.avif
---
Anschließend erstelle ich unter layouts/_partials die Datei cover.html und schreibe folgenden Code hinein:
{{- /* /layouts/_partials/cover.html */ -}}
{{- /* Handles cover-image generation */ -}}
{{- $cover := false -}}
{{- $autoCover := default $.Site.Params.autoCover false }}
{{- if index .Params "cover" -}}
{{- if .Resources.GetMatch .Params.Cover }}
{{- $cover = (.Resources.GetMatch .Params.Cover).RelPermalink -}}
{{- else -}}
{{- $cover = absURL .Params.Cover -}}
{{- end -}}
{{- else if $.Site.Params.AutoCover -}}
{{- if (not .Params.Cover) -}}
{{- if .Resources.GetMatch "cover.*" -}}
{{- $cover = (.Resources.GetMatch "cover.*").RelPermalink -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{if $cover -}}
<!-- Cover image found -->
<img src="{{ $cover }}"
class="post-cover"
alt="{{ .Params.cover_alt | plainify | default (.Description| plainify) }}"
title="{{ .Params.CoverCredit |plainify|default (.Title | plainify) }}" />
{{- end }}
Der Code sucht und extrahiert den Pfad zum Coverbild. Sollte ein valider Pfad gefunden werden, wird es als post-cover mit entsprechendem CSS angezeigt.
Dem XML-Template füge ich als erstes Element innerhalb des <description>-Tags das Coverbild hinzu. Erst danach kommt der eigentliche Artikel. Die meisten Feed Reader nehmen dieses Bild dann als Cover für ihre Übersichten.
Manuelle Anpassungen: Layouts#
Damit sich meine Seite in Hugo weiterhin ganz ähnlich anfüllt wie zuvor in Jekyll muss ich in den Layouts ein paar Änderungen vornehmen. Im Folgenden habe ich sie beschrieben.
baseof.html#
Hier werden die Basis-Inhalte definiert. Definitionen für Kopf- und Fußzeile werden importiert und Stylesheets eingebunden. Die allermeisten oben beschriebenen Änderungen werden an dieser Stelle importiert.
{{- /* /layouts/baseof.html */ -}}
<!DOCTYPE html>
<html lang="{{ $.Site.Language }}">
<head>
{{ if .Param "math" }}
{{ partialCached "math.html" . }}
{{ end }}
{{ block "title" . }}
<title>{{ if .IsHome }}{{ $.Site.Title }}{{ else }}{{ .Title }} :: {{ $.Site.Title }}{{ end }}</title>
{{ end }}
{{ partial "head.html" . }}
<link rel="stylesheet" href="{{ "/assets/css/gallery.css" | relURL }}">
<link rel="stylesheet" href="{{ "/assets/css/media.css" | relURL }}">
</head>
<body>
{{ $container := cond ($.Site.Params.FullWidthTheme | default false) "container full" (cond ($.Site.Params.CenterTheme | default false) "container center" "container") }}
<div class="{{- $container -}}{{- cond ($.Site.Params.oneHeadingSize | default false) " headings--one-size" "" }}">
{{ partial "header.html" . }}
<div class="content">
{{ block "main" . }}
{{ end }}
</div>
{{ block "footer" . }}
{{ partial "footer.html" . }}
{{ end }}
</div>
</body>
</html>
list.html#
Für Übersichtsseiten wie Artikel, Tags, Projekte benötige ich eine Listenansicht. Dabei möchte ich je vier Artikel in einer Zeile anzeigen. Jeder Artikel bekommt ein eigenes “Kärtchen” mit Titelbild (cover), Titel, Kurzbeschreibung und - falls Verfügbar - weiteren Details wie Lesezeit. Hugos paginator crawlt den entsprechenden Ordner und stellt die Inhalte zusammen, wärend mein Stylesheet list.css Formatierung und Anzeige übernimmt.
{{- /* /layouts/_default/list.html */ -}}
{{ define "main" }}
<link rel="stylesheet" href="{{ "/assets/css/list.css" | relURL }}">
{{ with .Content }}
<div class="index-content">
{{ . }}
</div>
{{ end }}
<div class="posts posts-grid">
{{ range .Paginator.Pages }}
<article class="post on-list">
<a href="{{ .Permalink }}" class="post-card" aria-label="{{ .Title }}">
{{ partial "cover.html" . }}
<div class="post-card-body">
<h4 class="post-title">
{{ .Title | markdownify }}
</h4>
<div class="post-excerpt">
{{ if .Description }}
<p>{{ .Description }}</p>
{{ end }}
</div>
{{- if and (.Param "readingTime") (eq (.Param "readingTime") true) -}}
<div class="post-reading-time">
{{ .ReadingTime }} {{ $.Site.Params.minuteReadingTime | default "min read" }}
</div>
{{- end -}}
</div>
</a>
</article>
{{ end }}
{{ partial "pagination.html" . }}
</div>
{{ end }}
single.html#
Meine single,html ist fast identisch mit der Standardimplementierung von terminal. Ich habe lediglich die Möglichkeit hinzugefügt, ein zum Titel gehöriges “banner-image” zu haben, und importiere die _partial/cover.html-Vorschrift zum Laden eines Coverbildes.
<article class="post">
{{ with .Params.banner }}
<img
src="{{ . }}"
class="post-banner"
alt="{{ $.Params.banner_alt | plainify | default ' ' }}"
/>
{{ end }}
Bei all den Änderungen könnte man überlegen, ein eigenes Theme zu forken… 🤔
Qualitätskontrolle#
Neu ist für meine Website auch, dass ich auf tote Links prüfe. Die Seite ist erwachsen geworden und verfügt über so viele interne und externe Verlinkungen, dass dies manuell nicht mehr sinnvoll durchzuführen ist. Mit welchem Tool ich vorgehe und wie ich dabei Hugo-Eigenheiten berücksichtige, dokumentiert der Artikel zum Thema htmltest-Konfiguration für Hugo.
Veröffentlichung#
Auch für Hugo benötige ich eine automatisierte Pipeline. Sobald ich eine Änderung nach main schiebe, soll die Webseite automatisch neu gebaut und ausgeliefert werden. Wie das genau funktioniert beschreibe ich im Artikel Hugo-Website mit Github Actions in Docker bauen und ausliefern.
Leistung#
Was der ganze Aufwand jetzt gebracht hat? Für user ist Aussehen und Navigation sehr ähnlich zur Website in Jekyll. Die Verbesserungen machen sich allerdings durch schnellere Ladezeiten, geringere zu übertragende Datenmengen und bessere Übersichtlichkeit aus. Einendetaillierten Vergleich zwischen nehme ich im Artikel Jekyll vs. Hugo Benchmarking vor.