Wann ein Static Site Generator Sinn macht (und warum Lektor eine gute Wahl ist)

written on 2019-06-01, last updated on 2019-06-02

Die meisten auf Content fokussierten Websites werden auf Basis eines Content Management Systems (CMS) implementiert. Oft mit Wordpress, manchmal auch mit Drupal oder TYPO3, selten auch mal mit Schwergewichten wie Adobe Experience Manager oder Sitecore.

Gemeinsam haben diese CMS, dass die Website jeweils dynamisch aus Daten und Templates beim Abruf zusammengebaut wird. Bestenfalls liegt noch ein kurzzeitiger Cache dazwischen.

Dieses Pattern hat sich bewährt und bringt einen großen Vorteil: Es kapselt die Technik einer Website weg. Statt zu programmieren, können wir, nun ja, Content managen. Mit Hilfe eines CMS kann ich Inhalte komfortabel und flexibel ergänzen und aktualisieren.

Dafür muss ich aber an einigen Stellen zusätzlichen Aufwand in Kauf nehmen:

Die Technik muss generisch mit allen denkbaren Inhalten zurechtkommen. Das Layout der Seite ist nicht für eine bestimmte Überschriftenlänge passend, sondern für alle Überschriften, die sich ein Content Manager in der Zukunft ausdenken könnte.

Die Server, die die Website ausliefern, müssen performant genug sein, um ständig die abgerufenen Seiten dynamisch nach aktuellem Stand des Contents neu zu generieren. Komplexität und Anforderungen für den Server steigen.

Und nicht zuletzt muss dieses komplexere Setup auch noch sicher sein und bleiben. Je mehr Logik ein System enthält, desto mehr kann auch schief gehen. In jedem verbreiteten CMS werden irgendwann Sicherheitslücken gefunden – und meist auch behoben. Ich muss meinen Server aktuell halten.

Lohnt sich das alles?

Content Manager sollen Inhalte komfortabel und flexibel ändern können.

Oft stellt sich heraus, dass diese Anforderung an eine Website überhaupt nicht stimmt.

Je seltener eine Website aktualisiert wird, desto weniger sind die „Content Manager“ mit dem CMS vertraut. Egal, ob Freelancer oder Agentur: Oft rufen Kund_innen einfach an, wenn sie eine Änderung an ihrer Website haben wollen, oder schreiben eine E-Mail. Das ist auch total OK, denn dafür haben sie ja ihre Agentur.

Nur: Dann können wir auch die ganze komfortable Oberfläche eines CMS in Frage stellen, wenn am Ende doch Expert_innen die Inhalte pflegen.

Alternative: ein Static Site Generator

Bei einem Static Site Generator werden ebenfalls Inhalte in einem generischen Template als Seiten ausgegeben. Aber dieser Prozess passiert nur zum Zeitpunkt der Aktualisierung auf einem Computer, der kein öffentlicher Server ist. Am Ende hat er eine Reihe statischer HTML-Seiten erzeugt, die die komplette Website darstellen.

Diese statischen Seiten lassen sich viel leichter sicher und performant veröffentlichen als eine CMS-Applikation.

Welches Vorgehen für welche Seite?

Diagramm mit zwei Achsen: Lebensdauer und Aktualisierungshäufigkeit

Wenn eine Website voraussichtlich nicht mehr aktualisiert werden soll und eventuell nur für eine kurze Lebensdauer vorgesehen ist, lohnt sich der Aufwand für ein generisches Template nicht. Dann kann ich die statische Seite auch manuell zusammenbauen.

Wenn die Seite häufig aktualisiert wird (und die Content Manager daher entsprechend vertraut mit dem CMS sind), lohnt sich ein CMS.

In vielen anderen Fällen macht ein Static Site Generator Sinn.

Warum Lektor

Lektor ist ein Static Site Generator. Es gibt davon hunderte, https://www.staticgen.com hat eine filterbare Liste. Meine Gründe, für dieses Blog auf Lektor zu setzen sind:

  • Lektor basiert auf Python. Im Idealfall muss ich mich mit der Programmierung des Tools nicht auseinandersetzen, aber meist ist das doch irgendwann nötig.
  • Templates für Lektor werden mit dem Templating-System Jinja2 gebaut. Es gehört zum „Pallets“ Stack, rund um das HTTP-Framework Flask und ist entsprechend bewährt und weit verbreitet.
  • Lektor hat eine einfache Admin-Oberfläche, die ich lokal im Browser aufrufen kann. Damit kann ich neue Posts anlegen und schreiben – ein bisschen Komfort ist doch ganz gut.

A simplistic approach to auto-detect the language of a blog post

written on 2019-05-07

HTML wants you to declare the language of your page.

<html lang="en">

would say: "this page is in English". Why is it useful? Once the browser knows the language of your page, it can apply automatic hyphenation for example.

I like writing in both English and German. So the language might vary between blog posts. In order to correctly declare the language in the HTML of each post, I could add a field, where I explicitly state either "en" or "de" for each blog post that I create.

But writing is about content, not about wrangling meta-data. So there's got to be a better way, right? Let's use some AI algorithm.

The 100 most common words

Take the most common 100 words from both languages. For each word, check if it occurs in the blog post. The language which has more word occurrences wins.

Luckily, Wikipedia has lists of the most common 100 words for both English and German.

This can even be implemented in the (slightly limited) Jinja templating language, which Lektor (the static site generator that this blog is based on) uses:

{%- macro auto_detect_lang(text) -%}
  {%- set de_words = ["der", "die", "und", "..."]  -%}
  {%- set en_words = ["the", "be", "to", "..."] -%}

  {%- set contained_de_words = [] -%}
  {%- set contained_en_words = []  -%}

  {%- for word in de_words -%}
    {%- if word in text -%}
      {%- do contained_de_words.append(word) -%}
    {%- endif %}
  {%- endfor %}

  {%- for word in en_words -%}
    {%- if word in text -%}
      {%- do contained_en_words.append(word) -%}
    {%- endif %}
  {%- endfor %}

  {%- if contained_de_words|length > contained_en_words|length -%}
  de
  {%- else -%}
  en
  {%- endif %}
{%- endmacro %}

You can find the full code in the blog's git repository.

This will be my blog.

written on 2019-05-06

It will be

  • made with a static site generator (probably Lektor)
  • pragmatic
  • written in Markdown
  • fast and standards-compliant
  • generated and deployed via CI

Future extensions will add

  • search (maybe with a pre-generated index by Lunr.js)

The source is at https://gitlab.com/pixelistik/blog/