Themenskript aus dem Hydrierungsvergleich nehmen

Der Browser leert das Nonce-Attribut, sobald er das Element geparst hat - so
schreibt es die CSP-Spezifikation vor, damit kein Skript den Wert auslesen und
sich damit selbst nachladen kann. React vergleicht beim Hydrieren trotzdem das
Attribut, liest clientseitig den leeren Wert und meldet einen Unterschied, den
es nicht gibt.

suppressHydrationWarning an diesem einen Element sagt React, dass hier nichts
zu vergleichen ist. Das Nonce selbst bleibt: ohne es blockiert die Richtlinie
das Skript, und ohne das Skript blitzt beim Laden das falsche Thema auf.

Nachgewiesen gegen einen Entwicklungsserver: ohne das Attribut erscheint genau
die gemeldete Konsolenmeldung, mit ihm nicht.

Ein erster Versuch, das per Konsolenprüfung im e2e abzusichern, war auch ohne
den Fix grün - React meldet den Unterschied nur im Entwicklungsmodus, der
Testlauf nutzt den Produktionsbau. Die Prüfung ist wieder entfernt; eine, die
nicht anschlägt, ist schlimmer als keine. Stattdessen prüft
tests/thema-vorab.test.ts die drei Dinge am Skript, die zusammenpassen müssen:
Nonce, Hydrierungsausnahme und derselbe Speicherschlüssel wie im Umschalter.
This commit is contained in:
Harlekin
2026-09-03 17:26:40 +02:00
parent efdecf5664
commit 7f43bfc2a3
2 changed files with 66 additions and 1 deletions
+20 -1
View File
@@ -35,7 +35,26 @@ export default async function RootLayout({ children }: { children: React.ReactNo
return (
<html lang="de">
<head>
<script nonce={nonce} dangerouslySetInnerHTML={{ __html: THEME_SCRIPT }} />
{/*
`suppressHydrationWarning` wegen des Nonce, nicht wegen des Inhalts.
Der Browser **leert das Nonce-Attribut**, sobald er das Element
geparst hat — so schreibt es die CSP-Spezifikation vor, damit kein
Skript den Wert über `getAttribute` auslesen und sich selbst
nachladen kann. React vergleicht beim Hydrieren aber genau dieses
Attribut, liest clientseitig den leeren Wert und meldet einen
Unterschied, den es nicht gibt: unser Markup ist auf beiden Seiten
dasselbe.
Es bleibt bei einem einzigen Element mit einer Konstante als Inhalt,
deshalb ist die Unterdrückung hier eng genug. Der Nonce selbst
entfällt nicht: ohne ihn blockiert die Richtlinie das Skript, und
ohne das Skript blitzt beim Laden das falsche Thema auf.
*/}
<script
nonce={nonce}
suppressHydrationWarning
dangerouslySetInnerHTML={{ __html: THEME_SCRIPT }}
/>
{/* Nur die beiden Schnitte vorladen, die auf jeder Seite vorkommen. */}
<link
rel="preload"