forked from cms/tibi-svelte-starter
fix(ssr): Cache-Schreibfehler schlucken, App-Start absichern
Dieselbe Vorlage, dieselbe Auslieferung: `context.db.create("ssr", …)` ist
ein Insert, mehrere parallele Anfragen nach einer Invalidierung erzeugen
"duplicate key", und die Verlierer antworten mit 500 — ohne #appContainer,
also bleibt die Seite beim Besucher leer. Der Fehler wird geschluckt, die
Seite geht raus.
Der Block ist byte-gleich zu dem im event-website-tibi-2026-Projekt. Der
Starter ist die Vorlage; zwei Varianten desselben Fixes wären genau die
Drift, die hier nicht stattfinden darf.
Dazu der Einstiegspunkt, der denselben Fehlerklasse-Vorfall hat:
setupI18n().then(() => { hydrate(App, { target: appContainer }) })
Ein Fehler beim Laden der Locale-Datei oder ein werfendes hydrate()
lässt das ausgelieferte HTML stehen — ohne Signal, ohne Logeintrag, und für
einen Test nicht unterscheidbar von "noch nicht fertig". Jetzt steht der
Render in try/catch, der Fehler wird geloggt, und #appContainer bekommt
data-app-ready="error". Tests warten auf den Wert "true" und nennen bei
"error" die Ursache mit, statt still zu timeouten.
This commit is contained in:
+34
-5
@@ -3,9 +3,38 @@ import App from "./App.svelte"
|
||||
import { hydrate } from "svelte"
|
||||
import { setupI18n } from "./lib/i18n/index"
|
||||
|
||||
// Initialize i18n before mounting the app
|
||||
setupI18n().then(() => {
|
||||
let appContainer = document?.getElementById("appContainer")
|
||||
hydrate(App, { target: appContainer })
|
||||
})
|
||||
/**
|
||||
* Ein Fehlschlag beim Start darf nicht stillschweigend bleiben.
|
||||
*
|
||||
* Ohne i18n gibt es keine Labels, und `hydrate()` kann werfen, wenn das
|
||||
* Server-Markup vom Client abweicht. In beiden Fällen bleibt das
|
||||
* ausgelieferte HTML stehen: der Besucher sieht eine tote Seite ohne jeden
|
||||
* Hinweis, und für einen Test ist das nicht unterscheidbar von "noch nicht
|
||||
* fertig".
|
||||
*/
|
||||
function markBootFailed(stage: string, error: unknown) {
|
||||
console.error(`[app] Start fehlgeschlagen (${stage}):`, error)
|
||||
document?.getElementById("appContainer")?.setAttribute("data-app-ready", "error")
|
||||
}
|
||||
|
||||
// Initialize i18n before mounting the app
|
||||
setupI18n()
|
||||
.then(() => {
|
||||
let appContainer = document?.getElementById("appContainer")
|
||||
try {
|
||||
hydrate(App, { target: appContainer })
|
||||
} catch (error) {
|
||||
markBootFailed("hydrate", error)
|
||||
return
|
||||
}
|
||||
|
||||
// Signal "die App ist hydration gelaufen": erst gesetzt, wenn i18n
|
||||
// geladen und der erste Render abgeschlossen ist.
|
||||
//
|
||||
// Ohne das gibt es keinen zuverlässigen Zeitpunkt, an dem die Seite
|
||||
// fertig ist. `domcontentloaded` sagt nichts über den Zustand des
|
||||
// Containers aus, und wer auf "Inhalt vorhanden" wartet, wartet auf
|
||||
// etwas, das auch nach 15 s nicht kommen muss.
|
||||
appContainer?.setAttribute("data-app-ready", "true")
|
||||
})
|
||||
.catch((error: unknown) => markBootFailed("i18n", error))
|
||||
Reference in New Issue
Block a user