fix: use per-page blazor startup

This commit is contained in:
2026-05-04 23:58:26 +02:00
parent 56e0ec1e79
commit c628957163
8 changed files with 39 additions and 8 deletions

View File

@@ -26,6 +26,7 @@ The change is complete when a human can run the app, open `/`, observe the corre
- [x] (2026-05-04) Added expanded workspace startup diagnostics across Blazor lifecycle logging, route-content render logging, and browser-side DOM mutation snapshots to narrow the remaining Firefox batch-2 crash.
- [x] (2026-05-04) Extended the diagnostics to page-load time by wrapping the interactive host in a stable container and logging pre-Blazor body and host mutations before the first interactive batch applies.
- [x] (2026-05-04) Reworked authenticated route startup into phased interactive batches so the first render mounts only a tiny shell, the second render mounts a simple header placeholder, the third render mounts route skeletons, and real control-heavy content appears only after route initialization completes.
- [x] (2026-05-04 22:17Z) Removed global authenticated `Routes` interactivity, moved `InteractiveServerRenderMode(prerender: false)` onto the real authenticated pages, and switched to manual `Blazor.start({ ssr: { disableDomPreservation: true } })` startup based on the upstream Firefox guidance in `dotnet/aspnetcore#58824`.
## Surprises & Discoveries
@@ -56,6 +57,12 @@ The change is complete when a human can run the app, open `/`, observe the corre
- Observation: the RoboForm-triggered crash happens before any component `OnAfterRenderAsync` callback in the authenticated route tree.
Evidence: in the failing `/play` and `/admin` reproductions, the last server-side logs were only `OnInitialized` and `OnParametersSet` entries for `Workspace` and its immediate child components; there were no `WorkspaceRouteView.OnAfterRenderAsync` or `Workspace.InitializeRouteCoreAsync` entries before the circuit terminated.
- Observation: the current app still matched the upstream "global interactivity" failure shape even after the route-first rewrite, because `App.razor` continued to apply `@rendermode` to the root `Routes` component.
Evidence: `RpgRoller/Components/App.razor` still rendered `<Routes @rendermode="@(new InteractiveServerRenderMode(prerender: false))" />` until the final follow-up pass, while `dotnet/aspnetcore#58824` explicitly reports Firefox crashes for Global mode and says PerPage mode does not reproduce.
- Observation: once the authenticated pages moved to per-page interactivity, header route navigation needed full document reloads instead of in-circuit `NavigationManager.NavigateTo` transitions.
Evidence: the first Selenium run after the per-page render-mode change reached `/play` in the URL but never mounted `#skill-filter-input` after `/campaigns -> /play` until `Workspace.NavigateToRouteAsync` switched to `forceLoad: true`.
- Observation: the locally installed Snap Firefox build on this machine is viable for Selenium through `geckodriver`, but not for Playwright protocol control.
Evidence: Playwright stalled during the `-juggler-pipe` handshake, while a `geckodriver` plus Selenium session against `/snap/firefox/current/usr/lib/firefox/firefox` completed the same Milestone 1 verification successfully.
@@ -77,6 +84,10 @@ The change is complete when a human can run the app, open `/`, observe the corre
Rationale: the current `screen` preference in `sessionStorage` causes the app state and the browser URL to disagree. Real routes remove that mismatch and make refresh, deep-linking, and testing simpler.
Date/Author: 2026-05-04 / Codex
- Decision: stop using global authenticated interactivity and move the authenticated pages to per-page `InteractiveServerRenderMode(prerender: false)` with manual startup that disables SSR DOM preservation.
Rationale: upstream issue `dotnet/aspnetcore#58824` identifies Firefox failures tied to Global interactivity and explicitly notes that PerPage mode does not share the problem. The Blazor startup guidance also documents manual `Blazor.start` configuration for SSR options such as `disableDomPreservation`.
Date/Author: 2026-05-04 / Codex
- Decision: stage the rewrite in two layers: first introduce real routes while preserving existing feature behavior, then split the large workspace tree into route-owned subtrees.
Rationale: the current workspace is dense and risk-prone. A staged rewrite keeps the app working while the route model changes, and it gives the test suite meaningful checkpoints.
Date/Author: 2026-05-04 / Codex