knuspermagier.de
Der privateste Blog von Philipp.

Sideproject-Tagebuch: Blogchain (5)

Ich sprach letztens kurz davon, aber jetzt ist es soweit. Ich kann wieder Posts im Browser tippen, statt sie über PhpStorm hochladen zu müssen.

admin.png
Aussagekräftiger Screenshot

So siehts aus. Nicht hübsch, nicht hässlich, aber funktional. Ich warf zwar GraphQL raus, in aber trotzdem nicht komplett ohne eine neue Technologie unterwegs, denn ich benutze ein CSS Grid!! Wow!

Ansonsten alles schnell mit Vue, vuex, und axios zusammengeworfen.

Der Editor ist übrigens CodeMirror. Ich hatte zuerst versucht mich mit ProseMirror herumzuschlagen, aber alle Vue-Plugins sind... suboptimal (aber Philipp baut ja schon!). Außerdem gefiel mir der Markdown-Modus nicht so richtig. CodeMirror wirkt zwar etwas lahm, gefällt mir von der Darstellung aber am Besten.

Mein Lieblingsfeature, das ich noch nachgerüstet habe, was gleichzeitig eigentlich eins der Features war, warum ich überhaupt was neues bauen wollte: Der Editor markiert Wörter, die ich sehr häufig benutze und daher vor dem Veröffentlichen gerne aus dem Post lösche automatisch rot! Wie cool ist das denn.

Wie im Screenshot zu sehen, ist eines dieser bösen Wörter das unscheinbare Wörtchen dann. Teilweise benutze ich es vier bis fünf mal in zwei aufeinanderfolgenden Sätze, ich komme einfach nicht davon los. Die rote Unterlegung wird mich nun hoffentlich eines besseren belehren!

Bis dahin wünsche ich euch eine gute Nacht!

Mastodon

Seit ein paar Tagen ist Mastodon ja doch wieder ein bisschen mehr der heiße Scheiß, daher habe ich meinen mstdn.io-Account mal reaktiviert und versuche jetzt dort zu posten, statt auf Twitter. Oder so. Mal sehen, allgemein schreibe ich ja eigentlich eh kaum noch was in diese Twitter-ähnlichen Kanäle.

Für alle, die gar nicht wissen, was es damit auf sich hat, empfehle ich diesen Blogpost von Marcel. Viele Grüße!

Drei Abende mit GraphQL

Vor ein paar Wochen berichtete ich noch voller Vorfreude, dass ich mich endlich mit GraphQL beschäftige — am Beispiel des Adminpanels für Blogchain!

Nun kann ich voller Stolz berichten, dass das Adminpanel fertig, oder sagen wir, benutzbar, ist. Allerdings läuft die API jetzt doch ganz normal über eine REST-Schnittstelle.

“Warum?”, fragt ihr euch. Ist GraphQL dem werten Herrn Programmierer wieder nicht recht? Ist er so sehr gegen Facebook, dass es so sehr hasst wie React?


Naaaaja. Ich hab, um ehrlich zu sein, schon am Anfang gedacht, dass es wahrscheinlich ziemlich dumm ist, eine so komplexe Technologie, die man nicht mal eben so verstanden hat, in dieses Side-side-side-Projekt einzubauen, welches möglichst so laufen soll, dass es sehr wenig Zeit beansprucht, einfach funktioniert und auch in Zukunft leicht wartbar ist.

Bei GraphQL (und der Integration ins Frontend über vue-apollo) war es nun so, dass ich mich erst sehr freute, über die ganzen Sachen, die man sofort schön findet:

  • Strenge Typisierung von Parametern
  • “Automatisch” erstellte Dokumentation
  • Geile Schema-Files
  • Apollo hat ne Menge Sachen drin, die alles ziemlich magisch erscheinen lassen

Nach dem ersten Abend war ich also ziemlich zufrieden. Der Abend danach, der zeitlich gesehen wirklich auch innerhalb von 24 Stunden folgte, war schon gespickt mit etwas Frust. Ich musste viel nachlesen. Wie macht man File-Uploads, wie macht man dies, wie krieg ich jetzt das Backend wieder schön gemacht, wenn ich eine Schema-File benutzen will. Warum sind die Queries und Mutations so super viel Schreibaufwand.

Trotzdem schaffte ich alles, was ich mir vorgenommen hatte und legte die Sache beiseite.

Einige Monde später, tatsächlich sogar eine ganze totale Mondfinsternis (dazu später mehr), schaute ich mir den ganzen Scheiß wieder an und wollte noch eben einen der letzten Todo-Punkte angehen: Authentifizierung. Nicht übel für ein Adminpanel, oder?

Mittlerweile hatte ich natürlich komplett vergessen, wie dieser ganze Apollokram funktioniert, und ich hatte auch nicht mehr so richtig Lust auf große Mutations und optimistische UI-Updates, die nur dafür sorgen, dass ich noch mehr dämliche Queries schreiben muss.

Nach dem dritten Abend hatte ich eine funktionierende Authentifizierung (ich brauchte dafür keinen ganzen Abend, ich investierte nur so 20 Minuten, ich hatte noch anderes zu tun!) und keine Lust mehr auf GraphQL.

Also baute ich es am vierten Abend alles aus. Normalerweise liest man ja immer diese Tweets, in denen Leute schreiben, wie viel Code sie löschen konnten, als sie von React/Redux auf Apollo umstiegen — bei mir sieht das jetzt komplett andersrum aus. Tausend Zeilen komische GraphQL-Queries weichen axios.get('/api/posts'). Das ist natürlich einfach nur witzig, ich verstehe schon, das es in einem Real-World-Projekt ganz anders aussieht — die ganzen Funktionen, die Apollo bringt, brauch ich nur gar nicht.


Nun könnte ich mich über die drei Abende ärgern, an denen ich etwas baute, was mittlerweile schon wieder gelöscht ist und nie benutzt wurde um einen Blogpost zu schreiben — aber das wäre Quatsch. Immerhin habe ich nun gelernt, was GraphQL ist!

Tatsächlich freue ich mich auch immer noch drauf, es in einem Projekt zu benutzen, das größer ist als das popelige Adminpanel dieses Blogs. Ich kann mir gut vorstellen, dass es in einer großen SPA eine richtige Daseinsberechtigung hat und eine Menge Spaß macht. Aber es ist halt, mit Apollo und all dem Kram der dazu gehört, ein richtig fettes Thema, mit dem man sich auseinandersetzen muss. Das muss sich schon lohnen.

Also, meine Empfehlung: Schaut es euch ruhig mal an, es könnte ganz cool sein. Nur halt nicht für die kleinen Quatsch-Projekte, mit denen man es ausprobiert. (Außer man nimmt sich mehr als drei Abende Zeit)

Wer viel misst, misst viel Mist

In der letzten Zeit ist es warm, schon gemerkt? Gefühlt wird es in der Wohnung, trotz nächtlichen Lüftens und geschickter Verwendung von Verdunklungs-Rollos, nie wirklich kühl. Um diesen Missstand mal wissenschaftlich zu belegen dachte ich mir, dass ich ja endlich mal ein paar smarte Thermometer anschaffen könnte. Eins in jeden Raum und dann geile Auswertungen, an denen ich sehen kann, dass alles viel zu heiß ist.

Nachdem ich feststellte, dass das Eve Degree immer noch 70 Euro kostet, legte ich das Projekt fast auf den großen Haufen der Projekte, die ich zu einer späteren Zeit angehen werde. Doch dann fiel es mir wie Schuppen von den Augen! Hej! Letztes Jahr habe ich doch ein Vermögen in smarte Thermostate von Tado investiert. Die messen doch auch ständig die Raumtemperatur und schicken sie sicher in die Cloud!

Ein googeln später wusste ich, wie man mit der API spricht. Die ist natürlich nicht offiziell verfügbar, aber auch nicht sonderlich geschützt. Alles ziemlich standardmäßige REST-Ware. Schnell hatte ich ein schmutziges Skript zusammengeschustert, mit dem ich alle Messungen, seitdem ich die Dinger habe, exportieren konnte. Keine Ahnung, wie lang die das speichern, aber mindestens 9 Monate!

Weil ich nicht weiß, womit ich sonst Grafen malen soll, importierte ich die Daten fix in eine InfluxDB (sehr gute Software! Später mehr! Hahaha, als ob.) und kreierte mit Chronograf folgende Grafik:

messung.png

Wie man sieht ist es wirklich ziemlich warm hier. Puh. Tagsüber kommt man selten unter 28°C Raumtemperatur und das neue ganznächtliche Lüften des Arbeitszimmers bringt auch gerade mal ein kleines Bisschen Erfrischung mit sich: 22°C, für wenige Minuten.


Nachdem der Graf gemalt war, fragte ich mich, was das eigentlich soll. Auch ohne es zu sehen, ist mir seit drei Monaten klar, dass es viel zu warm ist. Immerhin habe ich damit Material für diesen Blogpost erzeugt!

foto-eosscan-5

eos5scan31.jpg

Vor Ewigkeiten machte ich ja mal ein paar analoge Fotos, mit der EOS 5 von Papa. Monate später scannte ich die Negative mal. Naja. Das hier sieht irgendwie ziemlich künstlerisch aus, vor allem wegen dem ganzen Staub auf dem Scanner.

Volltext-Suche mit Redis

Einer meiner Punkte auf der Todo-Liste für Blogchain war natürlich auch eine Suche. Ständig suchte ich im Wordpress-Blog nach Dingen, die ich irgendwann mal geschrieben habe. Auf dieses Feature verzichten kam also nicht in Frage!

Doch wie?

  1. Die “Viel zu viel Zeit”-Lösung: Einfach komplett selber bauen
  2. Die “Zu viel Zeit und komplett verrückt”-Lösung: Elastic Search aufsetzen
  3. Die “Könnte gerade richtig sein”-Lösung: RediSearch

Ab Version 4.0 unterstützt Redis, der Key-Value-Store meiner Wahl, der hier zum Beispiel auch alle Posts im Cache behält, Module. Eins ist zum Beispiel RediSearch, eine mit ziemlich vielen Features ausgestatte Volltext-Suche.

Wie leicht es war, das nun hier zu integrieren, können wir uns jetzt mal anschauen.

Redis 4.0 & Debian

Das erste Problem ist leider, dass Debian natürlich nicht mit Redis 4 shippt. Zum Glück ist Redis eine tolle Software ohne große Abhängigkeiten und lässt sich super einfach selbst kompilieren kein Problem. Ist das geschafft, installiert man noch das RediSearch Modul, ebenfalls schnell zusammenbauen. Eine Sache von fünf Minuten.

RediSearch-PHP

Nun kann man die Suche schon benutzen, aber die Redis-Befehle manuell zu benutzen ist natürlich mühsam. Zum Glück gibt es RediSearch-PHP. Kurz composer require ethanhann/redisearch-php ausgeführt und schon stehen uns ein paar tolle Klassen im Code zur Verfügung.

Anbindung

Der Dreh- und Angelpunkt ist der Index. Dort werden alle Daten abgelegt und er wird am Ende durchsucht. Statt jetzt ellenlange JSON- oder XML-Konfigurationsdateien anlegen zu müssen, kann man den Index schnell im Code erzeugen:

$postIndex = new Index($redis);

$postIndex->addTextField('title')
    ->addTextField('text')

try {
    $postIndex->info()
} catch(UnknownIndexNameException $e) {
    $postIndex->create();
}

Schon hat man einen Index, in den man jetzt Dokumente werfen kann, die title und text haben. Der try-catch-Block sorgt noch dafür, dass keine Fehlermeldung kommt, wenn man - aus Versehen - versucht einen Index doppelt anzulegen. Hinzufügen von Dingen ist nun ähnlich einfach:

$post = getPost(); // einen Post irgendwoher holen

$doc = $postIndex->makeDocument($post->id);
$doc->title->setValue($post->title);
$doc->text->setValue(strip_tags($post->text));

$index->replace($doc);

replace sorgt automatisch dafür, dass das Dokument im Index aktualisiert wird, falls es schon existiert. Zum Schluss nun das, worauf wir alle gewartet haben, die Suche!

$result = $index->search('Wurst');
var_dump($result->documents());

Das wars! Cool, oder?


Natürlich wäre es noch besser, wenn die Suche auch alte Posts aus dem Archiv findet. Darum kümmere ich mich vielleicht auch noch.


Ich bin froh, dass es neben ElasticSearch und all den anderen schwergewichtigen Lösungen mittlerweile auch RediSearch gibt. Es funktioniert und ist easy einzubauen und, soweit ich das beurteilen kann, zumindest für solche extrem kleinen Anwendungsfälle, wie ein Blog, ganz gut geeignet.

Als nächstes werde ich, glaube ich, versuchen, watched.li entsprechend zu erweitern. Die dumme Suche ist mir da schon lange ein Dorn im Auge und kann so sicherlich um einiges aufgewertet werden.

Sideproject-Tagebuch: Blogchain (2)

Es ist soweit, ich kümmere mich wieder mehr um das System, statt z.B. mal Posts zu verfassen. Egal. Ich hab hier und da noch ein paar Minuten investiert und vieles etwas runder gemacht:

  • Großes Code-Refactoring, vielleicht wird es ja doch nochmal veröffentlicht.
  • Alle Bilder haben nun srcset und sizes und werden per lazysizes.js lazy-geloadet. Ja, jetzt hat die Webseite wieder JavaScript, aber das war unvermeidlich. Dafür sind Pageloads auf Mobilgeräten erheblich schneller, da die Bilder in passenden Größen ausgespielt werden. Zukunft!
  • Das Bild im Footer ist auch wieder dynamisch. Durch das harte Caching hatte sich die Zufallsfunktion irgendwie erübrigt. Daher nun auch hier ein Bisschen JavaScript! Was man damit nicht alles tolles machen kann!
  • Durch die Optimierungen habe ich im Google Lighthouse Audit-Kram fast überall 100 Punkte. Abgesehen vom “3G w/ CPU Slowdown”-Ding – da fehlt aber auch nur das Critical Path-CSS, für das ich einfach zu faul bin.

So, jetzt ist das Projekt aber abgeschlossen. 🤡

Sideproject-Tagebuch: Blogchain (1)

Ihr kennt das — da schreibt man einen langen Post, dass man zu viel zu tun hat, der in der Hauptsache eine Entschuldigung dafür war, weil man den großen Screencast zum Thema “Wie baue ich meinen Blog auf Kirby um” abgeblasen hat und ein paar Monate später hat man aus Versehen ein eigenes Blogsystem geschrieben und sich die aufwendige Daten-Migration, die einer der Gründe war, das Kirby-Projekt zu stoppen, einfach gespart.

Hä, was für ein Satz.

Naja, wie auch immer. Blogchain wächst und gedeiht und macht mir leider wirklich Spaß, auch wenn man mal wieder diverse Räder neu erfindet und auch einfach ein paar mehr bestehende Komponenten benutzen könnte. Immerhin habe ich noch nich angefangen einen Markdown-Parser zu schreiben, auch wenn mich Parsedown mindestens schon drei Mal nervte.

Gestern baute ich ein paar nullable Return-Types ein, was dazu führte, dass ich auf PHP 7.1 updaten musste, Stammleser haben die circa 3-minütige Downtime sicher bemerkt und den Blog schmerzlich vermisst.


Damit ich meine Posts in Zukunft nicht in PhpStorm schreiben muss, dachte ich mir, es wäre fein, ein Webinterface zu bauen. Gleichzeitig berichtete Philipp Kühn , wie geil er GraphQL findet und, naja, irgendwann muss man sich ja mal damit beschäftigen. Also baute ich das Panel mit Vue und Apollo statt Vuex und baute ein GraphQL-Plugin für Blogchain. It works. Also, man müsste es mal fertig und benutzbar machen, aber an sich geht es.

Dieser Post entstand aber weiterhin in PhpStorm.


Seit Tagen hab ich ein .doc-File mit einem Rezept in der E-Mail-Inbox und suche daher nach einer guten Rezepte-App. Leider gibt es keine, die mich begeistert und mir fiel ein, dass ich nun dieses tolle Flatfile-CMS mit Webinterface, Plugin-Support, Custom Post-Types und GraphQL-API habe. Ob sich damit nich eine Rezepte-Datenbank abbilden lässt?

Na sichi! 🤓