CV laden

Debugging

Hydration, die an der Locale bricht, nicht am Markup

Der Server nahm Russisch aus der URL. Der erste Client-Lauf las navigator.language. Vue warf den Baum weg. Die Seite lief, der Fehler blieb versteckt, bis der Header sprang.

Auf /ru/notes zeigte der Sprachschalter einen Frame lang Deutsch. Vue hatte den Header-Teilbaum verworfen. Eine Hydration-Warnung heißt, Server-HTML und erster Client-Render stimmen nicht. Vue verwirft den Teilbaum und baut neu. Die Notizenseite reagierte weiter auf Klicks, also habe ich die Warnung ignoriert, bis der Chrome sprang.

Der Server-Entry liest die Locale aus dem Pfad. Der Client-Entry fiel beim ersten Paint noch auf navigator.language. Chrome auf dieser Maschine ist de-DE. Die Hälfte der Hüllentexte wechselte. Daten wechselten. Der Artikelbody kam als ru aus der API, nur die Hülle wich ab. Das reicht. Nutzer auf einer russischen URL sahen einen deutschen Header, bis die Hydration fertig war.

Der Mismatch war kein fehlendes Div. Es waren zwei Locale-Quellen auf einem Request.

Zwei Bäume weichen ab. Vue verwirft das Server-Markup dieses Teilbaums.
Zwei Bäume weichen ab. Vue verwirft das Server-Markup dieses Teilbaums.

Ein Locale-String

Quelle ist das URL-Präfix. nginx schickt unbekannte Präfixe schon weg. Node und Laravel bekommen en, ru oder de. Den Wert serialisiere ich in den Seitenstate, der Client liest ihn von dort vor dem ersten Render. navigator.language darf nach mount, als Vorschlag, nicht für den Baum.

Dasselbe gilt für Zeitzone und Theme. Ein Theme in localStorage kennt der Server nicht. Default auf beiden Seiten rendern, nach mount umschalten. Ein Blitz ist besser als ein verworfener Baum, der den Klick am falschen Knoten landet.

Auf dem Client habe ich außerdem Accept-Language in das i18n-Plugin gegeben, der Server ignorierte den Header. Zwei Bootstraps, zwei Antworten. Die API-Locale aus der URL gewann für den Body. Das Plugin gewann für die Hülle. Ein String im Payload schloss beides.

Locale am Rand festziehen. en-US auf en mappen, bevor Node und PHP sie sehen.
Locale am Rand festziehen. en-US auf en mappen, bevor Node und PHP sie sehen.

Wie ich es fange

Hydration-Warnungen sind im Vue-Prozess in der Entwicklung Fehler. Ich fahre eine Notiz-Detailseite, eine Liste, ein Admin-Formular. Ich lese nur den ersten Mismatch. Der Rest sind meist Kinder dieses Knotens.

Ungültiges HTML erzeugt dieselbe Klasse von Bugs. Ein div in einem p im Seed repariert der Browser-Parser. Der Client-Baum kann nie zum Server-String passen. Der Fix sitzt im Artikel-HTML, nicht in i18n. Das sah ich an einer langen Notiz, als die Locale schon fest war. Die Warnung sah gleich aus. Der Stack zeigte auf einen Absatz, nicht auf den Schalter.

Hydration schalte ich nicht ab, um das zu verstecken. SSR ist der Punkt des Frontends. Können sich die zwei Läufe nicht auf die Locale einigen, einigen sie sich auf nichts, das davon abhängt. Ein Production-Build, der die Warnung schluckt, liefert den Blitz trotzdem. Der Test ist eine russische URL in einem deutschen Browser, erster Paint, Header-Sprache.

Was ich daraus mitnehme

Ich achte auf den ersten Hydration-Mismatch und den ersten Paint des Headers, nicht darauf, ob Klicks noch gehen. Eine Seite, die auf Klicks antwortet, kann den Baum trotzdem verworfen haben.

navigator.language und Accept-Language vor mount traue ich nicht. Das URL-Präfix ist die Locale. Theme und Zeitzone warten bis nach der Hydration.

Die Regel, die ich behalte: ein Locale-String im Seitenstate, gelesen vor dem ersten Client-Render. Zeigt die Warnung auf einen Absatz, das Artikel-HTML prüfen. Hydration nicht abschalten.

Zurück zu Notizen