1. Blog

Vorgestellt: Hugo, der superschnelle Static Website Generator

Hugo ist ein Go-basierter Static Website Generator, der nicht nur mit seiner Geschwindigkeit überzeugt. Lesen Sie, was das Tool ausmacht und warum Hugo bei Ihrem nächsten Web-Projekt Sinn machen könnte.

Vorgestellt: Hugo, der superschnelle Static Website Generator

Was ist überhaupt ein Static Site Generator?

Im Detail habe ich diese Frage schon in dem Beitrag „Static Website Generator: Statisch ist das neue Dynamisch“ beantwortet. In Kurzform: Statische Webseiten Generatoren generieren eine komplette Webseite als statisches HTML beim Deployment, also bevor die Webseite nach Änderungen live geht.

Das klingt erstmal nach dem letzten Jahrhundert, nimmt aber mit den modernen Tools immer mehr Fahrt auf, so dass statische Webseiten wieder voll im Trend sind. Vorteile sind eine bessere Möglichkeit zur Pagespeed-Optimierung, also z.B. schnelle Ladezeit bei Mobile, und auch ein gewisses Maß an Sicherheit, ohne ständig ein CMS updaten zu müssen.

Warum ist Static Website Generator Hugo so beliebt?

Warum das eine Tool beliebter als das andere ist, ist nicht immer dem Zufall überlassen. Das hat oftmals gute Gründe. So auch bei Hugo.

  • Da Hugo auf Go-basiert kann es nahezu auf jeder Plattform ausgeführt werden
  • Die Generierung der statischen Seite ist rasend schnell, womit sich Hugo auch für größere Webseiten mit mehreren 1.000 Seiten eignet (hier schwächeln Node.js basierte Generatoren)
  • Die Entwicklung wird stetig vorangetrieben, so das ca. einmal im Monat ein neues Release mit Bugfixes und neuen Features erscheint
  • Die Community ist aktiv und man findet jederzeit Hilfe in Foren

Löst damit Hugo schon das beliebte CMS WordPress ab? Nein, im Vergleich zu WordPress sind statische Webseiten Generatoren generell noch sehr wenig verbreitet. Aber: immer mehr Webentwickler und Agenturen setzen z.B. Hugo ein, um schnellere Microsites, Landingpages und ganze Webseiten für Ihre Kunden zu erstellen.

Wie funktioniert Hugo?

Hugo funktioniert ähnlich wie andere Static Site Generatoren. Der Inhalt liegt nicht in einer Datenbank, sondern in einzelnen Markdown-Dateien, die über Ordner und das sogenannte Frontmatter strukturiert werden. Letzteres sind Meta-Informationen die über YAML oder TOML (oder JSON) angegeben werden. Klingt kompliziert, ist aber einfach, da es sich im Prinzip nur um Textdateien handelt. Kein kompliziertes SQL mehr. Keine getrennte Datenhaltung. Alle Informationen einer Webseite liegen in einem Ordner. Deshalb spielt Hugo auch gut mit Git zusammen, so dass eine lückenlose Versionierung der Webseite möglich ist.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
+++
date = "2017-05-26T13:58:29+02:00"
title = "test"
publishdate = "2017-05-25T13:58:29+02:00"
lastmod = "2017-05-27T13:58:29+02:00"
tags = ["test1", "test2"]
images = ["/uploads/41742fb09e5059a4a7670d10780019f7.jpg"]

+++

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Über Shortcodes lassen sich in Markdown Elemente einbinden, die ansonsten nicht möglich wären. Das macht Hugo besonders flexibel.

Das sind die Besonderheiten von Hugo

Hugo Pipes

Seit den letzten Versionen bietet Hugo auch eine Asset Pipeline mit dem Namen Hugo Pipes, wie man Sie z.B. von Ruby on Rails kennt. Allerdings beschränkt sich diese im täglichen Gebrauch auf CSS/SCSS und SVG. Und ganz ohne Node.js kommt das Ganze auch nicht aus, zumindest wenn man PostCSS z.B. mit Autoprefixer nutzen möchte.

Hier ein Beispiel, indem in der Entwicklungsumgebung nur Sass zu CSS umgewandelt und das Framework Tachyons eingebunden wird. In der Produktionsumgebung läuft zusätzlich Autoprefixer drüber, der Code wird minimiert und die Styles werden in die HTML-Datei inlined:

1
2
3
4
5
6
{{- $style := resources.Get "scss/style.scss" | toCSS (dict "includePaths" (slice "node_modules/tachyons-sass")) -}}
{{- if .Site.IsServer -}}
  {{ with $style }}<link rel="stylesheet" href="{{ .RelPermalink }}">{{ end }}
{{- else -}}
  {{ with $style | resources.PostCSS (dict "config" "postcss.config.js") | minify }}<style>{{ .Content | safeCSS }}</style>{{ end }}
{{- end -}}

SVG-Datein kann man mithilfe von Hugo Pipes ebenfalls inlinen. Das spart eine ganze Menge Post Processing, das man ansonsten mit Node.js umsetzen würde.

Stichwort Node: Javascript kann man zwar auch mit Hugo Pipes zusammenfassen und minimieren, aber Babel, ES6 und Co. sind für Hugo noch Fremdworte, und werden es vermutlich auch bleiben. Daher: wer auf modernes Javascript setzt, benötigt neben Hugo Pipes noch einen weiteren Build Workflow.

Go Templates

Ob Go Templates ein Vor- oder Nachteil von Hugo ist, darüber lässt sich streiten. Der Nachteil ist sicherlich, dass diese Templatesprache nicht so weit verbreitet ist wie die Node.js basierte Konkurrenz (z.B. Handlebars).

Allerdings ist die Templatesprache von Hugo relativ schnell erlernt und bietet mittlerweile eine ganze Menge an Hugo-spezifischen Funktionen, die das Bauen von Webseiten erleichtern. Mit Partials und Blocks lassen sich relativ leicht komplexe Layouts in einzelne Komponenten zerlegen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<!DOCTYPE html>
<html lang="de">
  {{ partial "head" . }}
<body>
  {{ partial "header" . }}

  {{ block "main" . }}{{ end }}

  {{ partial "footer" . }}
  
</body>
</html>

Im obigen Template baseof.html wird das Grundgerüst definiert. Die einzelnen Templates werden dann in dem Block „main“ in dieses Grundgerüst eingesetzt.

1
2
3
4
5
6
7
{{ define "main" }}
  <article>
    <h1>{{ .Title }}</h1>

    <div class="">{{ .Content }}</div>
  </article>
{{ end }}

Über Partials lassen sich einzelne Komponenten inkludieren. Das kann man von Grundprinzip ähnlich wie bei React aufbauen, ist aber natürlich bei weitem nicht so komfortabel.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<a class="link db w-50-m w-third-l inherit" href="{{ .RelPermalink }}">
  {{ with .Resources.GetMatch "*" }}
    <figure class="c-figure">
      <img class="o-image" src="{{ (.Fill "640x320").RelPermalink }}" alt=">
    </figure>
  {{ end }}
  <div class=">
    <div class="f4">{{ .Title }}</div>
    {{ with .PublishDate }}<div class=">{{ partial "components/date" (dict "context" $ date .) }}</div>{{ end }}
  </div>
</a>

Custom Output Formats

Von WordPress kennt man Custom Post Types. Also eine Erweiterung der vorhandenen Post Types post und page. Das ist mit Hugo auch möglich. Je „Section“ (gleich Unterordner, indem der Content liegt) kann man ein eigenes Template definieren. Dieses kann man auch manuell im Frontmatter eines Inhalts angeben.

Hugo geht aber noch einen Schritt weiter. Über Custom Output Formats kann ein Inhalt in mehreren und auch anderen Ausgabeformaten als HTML gerendert werden. Die Stärke spielt dieses System aus, wenn es um Googles Advanced Mobile Pages, kurz AMP, geht. Mit Hugo lassen sich nativ normale HTML-Version und AMP-Version parallel generieren. Alles was es dazu braucht, ist, das man das zusätzliche Ausgabeformat definiert und da wo es notwendig ist, ein gesondertes Template für AMP anlegt (z.B. für Bilder, da diese in AMP anders eingebunden werden als in normalem HTML).

config.toml:

1
2
3
4
5
6
baseURL = "http://example.org/"
languageCode = "de"
title = "My New Hugo Site"

[outputs]
  page = ["HTML", "AMP"]

baseof.amp.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html amp lang="de">
<head>
  <meta charset="utf-8">
  <script async src="https://cdn.ampproject.org/v0.js"></script>
  <script async custom-element="amp-form" src="https://cdn.ampproject.org/v0/amp-form-0.1.js"></script>
  <meta name="viewport" content="width=device-width,minimum-scale=1, initial-scale=1">
  <title></title>
  <link rel="canonical" href="{{ .Permalink }}" />

  <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>

</head>
<body>

  {{ partial "header" . }}

  {{ block "main" . }}

  {{ end }}

  {{ partial "footer" . }}
  
</body>
</html>

Fazit Hugo

Ich selbst habe in den letzten Jahren viele Static Site Generatoren ausgetestet und live für eigene oder Kunden-Webseiten eingesetzt. Auch wenn Go Templates gewöhnungsbedürftig sind und Komponenten in React einfach cleaner aussehen, erledigt Hugo in den meisten Fällen den Job besser als die Konkurrenz. Das Tool ist mittlerweile ziemlich ausgereift, so das sich mit Hugo nahezu alle Arten von Webseiten realisieren lassen.

Übrigens: Auch mit Hugo generierte Webseiten können dynamisch sein, wenn man ein wenig Javascript oben drauf setzt. So lässt sich sogar eine Suche realisieren. Und wer zur Contentfplege ein CMS nicht missen möchte, kann dies mit Lösungen wie Netlify CMS oder Contentful realisieren. Hugo ist daher nicht nur für Landingpages oder Microsites geeignet, sondern ebenfalls für Blogs und größere Webseiten.