Hugo: Markdown Render Hooks + webp = Noch schnellere Websites

Mit Hugo Markdown Render Hooks generiert man aus einfachem Markdown inviduelles HTML. Das ermöglicht den Einsatz von webp-Bildern plus <picture>.

Meine Websites Phlow.de und moritz.sauer.io baue ich mit Hugo. Die Beiträge verfasse ich in Markdown und seit Längerem wollte ich die Website beschleunigen, indem ich webp-Bilder nutze. Und dafür gibt es jetzt eine einfache Lösung.

Das webp-Format verkleinert Bilder in der Dateigröße besser als JPG. Subjektiv sehen die Bilder aber gleich scharf aus. Das Problem für die Verwendung von webp: nicht alle Browser unterstützen das Format.

Das Problem löst man leicht mit HTML, denn dafür steht das <picture>-Tag zur Verfügung. Dieses erlaubt den Einsatz von Bildern für verschiedene Bildschirmgrößen und lässt den Einsatz von Dateiformaten zu bzw. überlässt dem Browser die Wahl. Das sieht dann so aus:

<picture>
  <source type="image/webp" srcset="bild.webp">
  <source type="image/jpeg" srcset="bild.jpg">
  <img src="bild.jpg" alt="" />
</picture>

Während Safari weiterhin das jpg-Bildformat bevorzugt, nutzen Chrome und Firefox die webp-Variante.

webp-Bilder aus JPG und PNG-Bildern generieren

webp-Bilder generiert man einfach über das Mac Terminal. Damit das auf meinem Mac funktioniert, habe ich mit homebrew einfach das Werkzeug installiert:

brew install webp

Anschließend öffne ich den Ordner mit den Bildern im Terminal und zwei Schleifen für jpg- und png-Bilder konvertieren mir sämtliche Bilder im Ordner:

for i in *.jpg; do cwebp -q 90 $i -o "${i%.*}.webp"; done
for i in *.png; do cwebp -q 90 $i -o "${i%.*}.webp"; done

Vergleich komprimierter Bilder mit jpg, guetzli-jpg und webp

Das folgende Beispiel illustriert, wie die Bilder mit den Maßen 1600 × 1067 schrumpfen. Exemplarisch habe ich ein Bild von Unsplash runtergeladen und auf die Pixelmaße 1600 × 1067 verkleinert. Dann habe ich das Bild mit dem JPG-Komprimierer guetzli verkleinert und dann noch mit webp. Die Ergebnisse kannst Du über die folgenden Links öffnen und vergleichen.

Original JPG-Bild

JPG mit guetzli Qualität 85 optimiert

Bild mit webp und Qualität 80 optimiert

Hinweis: Wenn Du ältere Browser nutzt oder Safari (Stand 2020-06-18), dann wird Dir das Bild nicht angezeigt.

Hugo Markdown Render Hooks übernehmen die Arbeit

Beiträge schreibt man in Hugo in Markdown. Die Syntax für ein Bild mit Markdown lautet schlicht:

![Bildtitel](bild.jpg)

Das Problem ist: Und wie entsteht daraus das <picture>-Tag?

Dafür habe ich heute in den Hugo-News eine für mich neue Funktion entdeckt: die Markdown Render Hooks. Über diese hooks verändert man die Ausgabe der Markdown-Befehle. Anstelle eines normalen HTML-Bildbefehls realisiert man komplexeres HTML.

Mit einem hook erstellt man zuerst ein Rendering-Template, dass der Markdown-Parser Goldmark benutzt, wenn er z.B. ein Bild entdeckt. Diese Rendering-Templates legt man z.B. so ab:


.
├── _default
│   ├── _markup
│   │   └── render-image.html
│   ├── baseof.html
│   ├── blog_frontpage.html
...

substr ersetzt die jpg-Endung mit wepb

In meinem Fall sieht der Code von render-image.html so aus:

<picture>
  <source type="image/webp" srcset="{{ substr .Destination 0 -4 | safeURL }}.webp">
  <source type="image/jpeg" srcset="{{ .Destination | safeURL }}">
  <img src="{{ .Destination | safeURL }}" alt="{{ .Text }}" {{ with .Title}} title="{{ . }}"{{ end }} />
</picture>

Der kleine Trick ist in substr versteckt. Mit der substr-Funktion manipuliert man einen String. In diesem Fall schnappt sich substr den von Goldmark übergebenen Link, löscht die letzten drei Zeichen – hier jpg – und hängt anschließend das wepb dran.

Das feine an der ganzen Affäre: Beiträge schreibt man einfach, setzt ein Bild ein und Hugo übernimmt den Rest. Natürlich darf man nicht vergessen die webp-Bilder zu generieren.