Minimal funktionsfähiger Blog (Minimum Viable Blog)
(ostwilkens.se)- Ziel ist eine minimale Umsetzung: ein persönlicher Blog als statische Seite auf einer bereits vorhandenen Domain, der sowohl das Hinzufügen von Inhalten als auch grundlegendes SEO erfüllt
- Die Umsetzung bleibt einfach und besteht aus einer kleinen
template.html,markdown2, einem von O1 erstelltenrender.pysowie dem Schreiben von Markdown-Beiträgen - Das Template verwendet nur grundlegendes HTML/CSS wie
system-ui, maximale Breite70ch,color-scheme: light dark,viewportundUTF-8 render.pywandelt./posts/{post}/eng.mdin HTML um, passt Bildpfade an und erzeugt daraus./blog/{post}.htmlsowieindex.html- Es zeigt, dass sich auch ohne Jekyll, Ghost oder WordPress ein Blog allein mit statischem Rendering und Hosting betreiben lässt
Anforderungen an einen minimalen Blog und die tatsächliche Umsetzung
- Ausgangspunkt waren vier Anforderungen
- Eine bereits vorhandene Domain soll verwendet werden
- Moderne Webstandards sollen eingehalten werden und ein ordentliches SEO vorhanden sein
- Das Hinzufügen neuer Inhalte soll sehr einfach sein
- Alle Seiten sollen statisch gebaut werden
- Der tatsächliche Umsetzungsablauf ist einfach
- Eine kleine
template.htmlschreiben pip install markdown2ausführen- O1 um ein
render.py-Skript bitten - Beiträge schreiben, rendern und hosten
- Eine kleine
- Bestehende Blog-Engines wie Jekyll, Ghost oder WordPress werden nicht verwendet
Template und Rendering-Skript
template.htmlenthält nur die grundlegende HTML-Dokumentstruktur und minimales CSS- Mit
color-scheme: light darkwird ein Hell-/Dunkel-Farbschema festgelegt - Der Textstil ist auf
system-ui,sans-serif, maximale Breite70ch, Zeilenhöhe1.5und Schriftgröße1.25emgesetzt - Verwendet werden ein Home-Link mit
id="head-link"sowie der Platzhalter{{ content }}
- Mit
render.pykonvertiert Markdown-Beiträge mitmarkdown2in HTML- Das Eingabeverzeichnis ist
./posts, das Ausgabeverzeichnis./blog - Jeder Beitrag wird aus
./posts/{post_directory}/eng.mdeingelesen - Die erste
#-Überschrift wird als Beitragstitel verwendet - Markdown wird mit den Optionen
fenced-code-blocksundheader-idsumgewandelt - Der Bildpfad in
<img src="wird auf Basis von/posts/{post_code}/angepasst {{ content }}im Template wird durch das konvertierte HTML ersetzt, und auch der Titelstring wird durch den Beitragstitel ausgetauscht
- Das Eingabeverzeichnis ist
- Auch die Index-Seite wird im selben Skript erzeugt
greetings.mdwird zuerst in HTML umgewandelt- Die Titel aller Beiträge werden eingelesen und als Linkliste zu
/blog/{post_code}.htmlergänzt - Das Endergebnis wird als
index.htmlgespeichert
- Der Beitrag wurde am 2025-03-31 manuell verfasst
5 Kommentare
Ich betreibe meinen Blog derzeit auch genau so wie oben beschrieben. Ich habe ein SSG erstellt, das meine persönlichen Anforderungen erfüllt, und nutze es entsprechend. Um Thumbnail-Bilder, Kategorien und Tags verwenden zu können, habe ich jeweils eigene benutzerdefinierte Funktionen eingebaut. Die angehängten Bilder werden automatisch in WebP konvertiert und dann referenziert, wodurch ich mit der Rendering-Geschwindigkeit sehr zufrieden bin.
Oh, fügt ihr solche benutzerdefinierten Funktionen direkt hinzu, indem ihr den Code selbst schreibt? Ich versuche auch immer, alles als DIY zu machen, zögere dann aber wegen der Erweiterungen und Plugin-Funktionen, die die bisher von mir verwendeten SSG-Blog-Frameworks bieten.
Wenn man den Ehrgeiz etwas zurücknimmt, ist der Rest gar nicht so schwierig. Auch
ssgschreibt auf Anfrage an die AI den ganzen Code, und wenn man sie bittet, Funktionen hinzuzufügen, ergänzt sie die in Wirklichkeit auch alle, haha.Wenn man einfach nur eine schöne Schrift auswählt, ist es schon ganz ansehnlich.
Hacker-News-Kommentare
Diese Grafik aus dem Blogpost kommt mir in den Sinn: https://molodtsov.me/2023/02/how-to-start-your-blog-in-2023/
Ich bin im Sumpf der Static Site Generators (SSG) versunken, und am Ende habe ich die meiste Zeit damit verbracht, über den SSG selbst zu schreiben und daran herumzubasteln, statt die Texte zu schreiben oder die Dinge zu tun, die ich eigentlich vorhatte.
Am Ende habe ich den SSG aufgegeben, WordPress installiert und mich nicht weiter darum gekümmert — das war eine große Befreiung.
Wenn das Ziel ist, zu basteln und über diesen Prozess zu schreiben, ist das natürlich okay, und auch für Menschen, bei denen das Basteln das Schreiben nicht behindert. Ich gehöre aber nicht dazu.
Das Letzte, was man in dem Moment braucht, in dem man schreiben will, ist ein Vorwand zum Aufschieben.
WordPress und alle Plugins können kompromittiert werden, wenn man sie nicht aktuell hält, und der BDFL ist jemand, der aus belanglosen persönlichen Gründen den Zugang zum Senden oder Empfangen von Sicherheitsupdates blockieren kann.
Bei statischen Seiten gibt es keine Sicherheitslücken zum Patchen, daher ist es nicht weiter schlimm, wenn ein SSG-Projekt wegen Problemen des Maintainers komplett zerfällt — bei WordPress ist das dagegen sehr wohl kritisch.
Dann brauchte ich eine Möglichkeit für Besucher, Kommentare zu hinterlassen, also habe ich Disqus hinzugefügt, und am Ende wurde alles zu einem Mischmasch aus mehreren Diensten und viel JavaScript.
Vor ein paar Jahren wollte ich meine Daten wieder selbst besitzen und nicht mehr von externen Diensten abhängen, habe die Disqus-Kommentare exportiert, mit Serendipity herumprobiert und bin schließlich bei WordPress gelandet.
Ich konnte Kommentare und Markdown-Seiten importieren, und es gab sogar ein Plugin, das alles ins Fediverse veröffentlicht hat.
Seit ich es mit SQLite betreibe und automatische Updates aktiviert habe, braucht es praktisch keine Wartung mehr.
Es braucht zu viel Wartung für Funktionen, die man wahrscheinlich gar nicht benötigt. Wenn man es nicht aktuell hält, kann es Teil eines Botnets werden.
Für die meisten Blogs reicht ein Static Site Generator völlig aus, und selbst wenn Wartung nötig ist, kann ich sie dann erledigen, wenn ich es will.
Was ich wirklich wollte, war ein einzelner Befehl zum Veröffentlichen und eine einfache Möglichkeit, Bilder in einen Beitrag zu ziehen. Ersteres funktioniert gut, Letzteres geht über die Publishing-Funktion für Jupyter Notebooks.
Was ich absolut nicht wollte, war eine Lösung, bei der das „Senden von HTML an den Client“ den Overhead einer Datenbank oder Ähnlichem mit sich bringt.
Gut, aber ich finde, um es einen Blog zu nennen, braucht es noch zwei kleine Funktionen.
Erstens sollten Beiträge chronologisch sortiert sein, mit dem neuesten zuerst, und das Datum sollte irgendwo angezeigt werden. Wenn man es minimal halten will, reicht dafür Metadaten in der Beitragsdatei, etwa die Erstellungszeit.
Zweitens braucht man natürlich einen RSS-Feed. Mit dem bestehenden Skript und einer minimalen RSS-Vorlage ließe sich wohl leicht ein einfacher Feed nur mit Links und Titeln erzeugen.
„Gefolgt“ zu werden ist nicht immer gut und kann Druck erzeugen, sich an den Lesern auszurichten. Genau das ist einer der Faktoren, die Social Media schlecht machen.
Bei Punkt 1 tendiere ich inzwischen dazu, automatisch eine Datei mit Metadaten zu erzeugen, etwa in einem Format wie TOML.
Punkt 2, RSS, werde ich definitiv hinzufügen, aber das hängt von Punkt 1 ab :-)
Ich mochte schon immer unabhängige Websites, und meine eigene Website hat vor etwa 25 Jahren ganz ähnlich angefangen.
Damals war Classic ASP die einzige passende Technologie, die ich kannte, also habe ich sie in minimaler Form einfach nur mit ASP gebaut.
Heute läuft sie als statisch generierte Website in Common Lisp, und diese Konfiguration wird vermutlich die langfristige Lösung sein: https://github.com/susam/susam.net/blob/main/site.lisp
Als einfacher Satz statischer Seiten anzufangen, war ein guter Weg, um eine minimal funktionsfähige Website zu bauen, aber mit der Zeit brauchte ich Features wie RSS-Feeds, eine Blogliste in chronologischer Reihenfolge, einen Index nach Tags, Unterstützung für Nicht-Blog-Inhalte wie Tools, Spiele und Demos sowie Kommentare ohne Drittanbieter.
Jedes Mal, wenn die Anforderungen gewachsen sind, ist auch der Quellcode mitgewachsen, sodass aus ein paar hundert Zeilen inzwischen etwa 1300 Zeilen Common Lisp geworden sind.
Trotzdem möchte ich es auf einem Niveau halten, bei dem ich den gesamten Code auf einmal im Kopf behalten kann und Bugs innerhalb von 10 Minuten durch Nachdenken finden und beheben kann.
In letzter Zeit bin ich versucht, eine Blogroll hinzuzufügen, die eine Liste von Beiträgen meiner Lieblingsblogger bereitstellt. Das könnte zwar einen Feed-Reader ersetzen, aber ich versuche darauf zu achten, dass es nicht zu etwas anwächst, das am Ende sogar E-Mails liest.
Den Quellcode gibt es hier: https://github.com/brilee/modern-descartes-v2/blob/master/ma...
Enthalten sind RSS-Feeds, eine chronologische Blogliste, ein Tagging-System und ein lokaler Entwicklungsserver mit Dateiüberwachung und automatischer Neukompilierung.
Die aktuelle Version bleibt bei einem Python-Skript mit weniger als 1000 Zeilen: https://github.com/llimllib/obsidian_notes/blob/c93b9b5c46fe...
Ich habe abgeleitete Seiten wie Artikelsammlungen, Indizes und Slideshows gebaut und auch Tag-Varianten für Menschen und Videospiele erstellt.
Außerdem kann ich Look and Feel allgemeiner Widgets wie Thumbnail-Galerien oder Zitatboxen vollständig kontrollieren.
Das könnte als Referenz auf höherer Ebene nützlich sein.
Später will man vielleicht auch Shader und Webspiele einbetten, und ich hoffe, dass die Komplexität dabei nicht zu groß wird.
Es wäre schön, wenn Browser text/markdown und text/gemini nativ unterstützen würden.
Wenn ein Browser PDF rendern kann, sollte es doch nicht so schwer sein, einen einfachen Formatter für Markdown-/Gemini-Inhalte plus ein vom Nutzer festlegbares Stylesheet einzubauen.
Schon jetzt kann man zwar einen text/plain-Blog betreiben, aber weil es kein echtes Hypertext ist, verliert man bei SEO. Vielleicht lässt sich mit dem
link-Header irgendeine Magie anstellen.Unterstützung für weitere Formate würde die Hürde für sauberes Publizieren senken und den Nutzern die Kontrolle zurückgeben.
Zuerst müssten sich die Browser darauf einigen, welche Markdown-Varianten und Erweiterungen verwendet werden sollen. Markdown ist fast so etwas wie das CSV der Textformate, weil es jeder auf seine eigene Weise benutzt.
Wenn man es zu minimal hält, wird es Beschwerden geben, dass es nutzlos sei, und wenn man Erweiterungen auswählt, wird man hören, es sei aufgebläht.
Selbst wenn man die kurz- und langfristigen Vor- und Nachteile sorgfältig diskutieren will, könnte das mit dem Spruch „Lass nicht das Perfekte der Feind des Guten sein“ abgewürgt werden.
Und selbst wenn man sich auf einen bestimmten Funktionsumfang einigt, ist fraglich, ob es überhaupt genug Nutzen bringt.
PDFs direkt im Browser zu lesen, ist hinreichend verbreitet, aber vom direkten Lesen von Markdown würden vermutlich nur ein Teil der Softwareentwickler weltweit und vielleicht fünf seltsame Leute profitieren.
Deshalb würde es mich nicht überraschen, wenn ich in meinem Leben kein natives Markdown-Rendering im Browser mehr sehe.
Statt auf native Browser-Unterstützung zu warten, gibt es auch Bibliotheken für XSLT, die man verwenden kann, wenn man neue Versionen braucht, und ebenso Bibliotheken für diverse Formate wie jpegxl.
Wenn
html_content = html_content.replace('Minimum viable blog', title)verwendet wird, bedeutet das dann, dass jedes Vorkommen der ZeichenketteMinimum viable blogim Text durch den aktuellen Artikeltitel ersetzt wird? Das wäre doch ein Bug, oder?Der Code im Beitrag war ein erster Entwurf von O1, und diese Zeichenkette wurde durch
{{ title }}ersetzt.Ich experimentiere seit etwa 15 Jahren mit dem Minimal-Blog, und dabei habe ich ein paar Tricks gelernt.
const title = lines.match(/# (.+)/)[1]reicht schon aus, sodass man auf Frontmatter verzichten kann.Meine Blogs hatten nie so viele Beiträge, dass ich Paginierung, Tags, Kategorien oder Sortierung gebraucht hätte.
JSX ist mit fragwürdigen Hacks wie https://immaculata.dev/guides/enabling-jsx.html als reiner serverseitiger String-Builder ziemlich gut brauchbar.
Inzwischen ist es mit GitHub Pages und Dingen wie https://immaculata.dev/guides/using-gh-pages.html auch einfacher geworden, statt Jekyll einen beliebigen Build-Schritt zu verwenden.
highlight.js ist fast der König der einfachen Code-Syntaxhervorhebung, weil man nur drei Zeilen in das HTML einfügen muss, und shiki ist zwar schick, aber langsam.
Mit einem Standard-Framework für statische Blogs wie Hugo/Zola + Cloudflare Pages ist es einfach
Mein Blog ist ebenfalls eine minimale Konfiguration mit weniger als 100 KB und erfüllt alle Kriterien, die der Autor des Originalbeitrags aufgelistet hat
Ich nutze das Theme Hugo Blog Awesome, habe die 512-KB-Richtlinie befolgt und die Seitengröße überprüft sowie Bilder und unnötiges JS entfernt. Von Letzterem gab es von Anfang an nicht viel
Referenz: https://512kb.club, https://radar.cloudflare.com/scan
Ich habe eine Zeit lang ein „MVB“ betrieben, meines war aber noch einfacher
Ich hatte einfach eine einzelne HTML-Seite, schrieb Beiträge als
.txt-Dateien und aktualisierte die Startseite manuellEs war ziemlich wortreich, aber ich fand es trotzdem einfacher, als sich mit dem modernen Web herumzuschlagen
Später bin ich zu etwas Ausgefeilterem gewechselt und nutze jetzt Astro für meine persönliche Website und meinen Blog, und es ist wirklich großartig
Astro behauptet auf seiner Landingpage, die beste Plattform für „content-driven websites“ zu sein, und nach 6 Monaten Nutzung stimme ich dem zu
Für fast alles, was man zum Erstellen eines Blogs braucht, bietet es klare, leicht nachvollziehbare Konventionen und lässt den überflüssigen Ballast weg
Ich habe auf einigen Websites mit einem Ansatz experimentiert, der Bun JS und HTML innerhalb von JavaScript-Strings verwendet
Bun hat ein
—hot-Flag, das statisches HTML bei Änderungen neu erzeugtDie IntelliJ-IDE erkennt den Kommentar
// language=htmlüber einem String und formatiert das darin enthaltene HTML, inklusive Syntax-HighlightingWenn man statt einer Template-Sprache reine JavaScript-Funktionen verwendet, kann man die benötigte Logik direkt selbst schreiben, ohne erst nachzuschlagen, wie man es in der Template-Sprache macht
Ich hatte genug von Websites, die so aufgebläht sind, dass sie ewig zum Laden brauchen, deshalb verwende ich für meinen Blog einen sehr ähnlichen Ansatz: https://blog.borrego.dev
Quellcode: https://github.com/agubelu/blog