Commit 468a58a
* fix(ssr-overlay): remove overlay only after the routed page DOM settles (real home-page flicker)
Follow-up to #1318. On a real instance (VSB / dev-6.pc), an incognito Ctrl+Shift+R
still flickered: the deployed code dropped the SSR snapshot ~3.2s in, while the home
page was only half-rendered (search box, community list and several navbar items not
yet present, content showing "Recent Submissions") and then everything popped into
place ~600ms later. Captured frame-by-frame against the live instance.
Root cause: the home page renders piecewise (each section fetches its own data), so the
previous "<ds-app> has #main-content and height>=200" heuristic was satisfied while the
page was still building -> snapshot removed too early -> visible flicker.
Fix: after the auth/theme gate opens, keep the snapshot until the real <ds-app> subtree
has SETTLED -- no element added/removed for SETTLE_QUIET_MS (600ms) -- via a
MutationObserver, requiring minimum content first and capped at SETTLE_MAX_MS (10s). This
stays decoupled from ApplicationRef.isStable (DOM-settle ignores non-rendering background
async), so it does not bring back the post-login non-interactive page (#725): admin
reveals in ~5s, not ~15s.
Validated against the live dev-6.pc instance by intercepting the overlay-removal and
driving it with this condition:
- anon reload : drops @ ~4.8s, page COMPLETE (search + community list + full navbar)
- admin reload: drops @ ~5.0s (reason "settled", not the cap), page complete
vs the deployed code dropping @ ~3.2-3.6s on a half-built page.
Refs: dspace-customers#725, PR #1288, PR #1317, PR #1318
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(ssr-overlay): make the masked page interactive + skip overlay under WebDriver (close #725)
Addresses an expert review of the DOM-settle change: DOM-settle alone shortened but did not
eliminate issue #725, because the masking window still left the page non-interactive (the opaque
overlay sat over a visibility:hidden <ds-app>, so clicks landed on nothing) and still produced
duplicate DOM that breaks strict-mode E2E locators.
Changes:
- index.html: drop the `ds-app[data-dspace-ssr-hidden]{visibility:hidden}` rule and give the overlay
min-height:100vh. The overlay is already opaque + pointer-events:none, so it still masks the CSR
rebuild visually, but clicks now pass THROUGH it to the real, still-visible <ds-app> underneath.
The page is therefore interactive the entire time it is masked -> #725 ("looks rendered but
nothing is clickable") cannot recur, even if removal rides the 10s cap. The snapshot is marked
aria-hidden so AT (and the duplicate-node concern) target the live app, not the snapshot.
- index.html: also bypass the overlay for WebDriver runners (navigator.webdriver), mirroring the
existing Cypress guard, so Playwright/Selenium see no overlay and no duplicate DOM (fixes the
#725 strict-mode locator failure).
- app.component.ts: exclude the admin-sidebar subtree from the DOM-settle MutationObserver (its long
:enter/:leave animations would keep re-arming the quiet window and push admin logins toward the
cap); add OnDestroy + takeUntil + observer/timer teardown.
- Fix stale `ApplicationRef.isStable` / `removeSsrOverlayWhenStable` comments (index.html, typings.d.ts).
Verified against the live build (Playwright, CPU/network throttled):
- WebDriver run: overlay absent (no duplicate DOM).
- webdriver spoofed false (real-user path): a navbar click WHILE the snapshot is still shown reaches
the live <ds-app> (interactive under mask).
- anon reveal settled, CLS after reveal = 0; admin reveal settled (reason "settled", not cap),
CLS after reveal = 0.
Refs: dspace-customers#725, PR #1288, PR #1317, PR #1318, PR #1321
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* refactor(ssr-overlay): declarative DOM-settle, drop fragile admin-sidebar hack (no behaviour change)
The overlay-removal logic was a hard-to-read imperative blob (mutable done/quietTimer/capTimer flags,
manual arm/re-arm, manual MutationObserver/teardown bookkeeping) plus a brittle string-selector hack
(`inAdminSidebar` -> `closest('ds-themed-admin-sidebar, ds-admin-sidebar')`).
Rewritten as small, named, single-responsibility pieces:
- removeSsrOverlayWhenContentVisible(): guard + runOutsideAngular + subscribe(takeUntil(destroyed$)).
- routedPageReadyToReveal$(): loader gate (take 1) -> switchMap(dsAppDomSettled$).
- dsAppDomSettled$(): MutationObserver wrapped as an Observable; settle = startWith + debounceTime
(the quiet window) + filter(real content); race() with timer() for the cap; take(1).
- dsAppHasRenderedContent(), isElementChildListChange(), runAfterNextFrame(): tiny pure helpers.
RxJS now owns debounce, the cap, and teardown (the Observable disconnects the observer on unsubscribe,
takeUntil(destroyed$) ends everything on destroy), so the mutable flags, manual timers and the separate
cancelOverlaySettle field are gone (net -45 lines).
Dropped the admin-sidebar exclusion entirely: it was a fragile, theme-coupled selector guarding a
problem that interactive-under-mask already makes harmless (riding the cap is fine when the page is
clickable throughout) and that does not occur in practice (admin still settles via "settled", not the
cap). Tuning constants moved to named readonly fields.
Behaviour re-verified on the live build (Playwright, throttled): interactive-under-mask still works;
anon + admin both reveal with reason "settled" (not cap) and CLS after reveal = 0.
Refs: dspace-customers#725, PR #1321
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent dce52f0 commit 468a58a
4 files changed
Lines changed: 167 additions & 108 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| |||
131 | 131 | | |
132 | 132 | | |
133 | 133 | | |
134 | | - | |
| 134 | + | |
| 135 | + | |
135 | 136 | | |
136 | 137 | | |
137 | 138 | | |
138 | 139 | | |
| 140 | + | |
139 | 141 | | |
140 | 142 | | |
141 | 143 | | |
| |||
144 | 146 | | |
145 | 147 | | |
146 | 148 | | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
147 | 155 | | |
148 | 156 | | |
149 | 157 | | |
| |||
155 | 163 | | |
156 | 164 | | |
157 | 165 | | |
| 166 | + | |
158 | 167 | | |
159 | 168 | | |
160 | | - | |
| 169 | + | |
161 | 170 | | |
162 | 171 | | |
163 | 172 | | |
| |||
169 | 178 | | |
170 | 179 | | |
171 | 180 | | |
172 | | - | |
173 | 181 | | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
174 | 185 | | |
| 186 | + | |
175 | 187 | | |
176 | 188 | | |
177 | 189 | | |
| |||
184 | 196 | | |
185 | 197 | | |
186 | 198 | | |
187 | | - | |
| 199 | + | |
188 | 200 | | |
189 | 201 | | |
190 | 202 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| |||
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
20 | | - | |
| 21 | + | |
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
| |||
39 | 40 | | |
40 | 41 | | |
41 | 42 | | |
42 | | - | |
| 43 | + | |
43 | 44 | | |
44 | 45 | | |
45 | 46 | | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
46 | 59 | | |
47 | 60 | | |
48 | 61 | | |
| |||
94 | 107 | | |
95 | 108 | | |
96 | 109 | | |
97 | | - | |
98 | | - | |
| 110 | + | |
| 111 | + | |
99 | 112 | | |
100 | | - | |
101 | | - | |
102 | | - | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
108 | | - | |
109 | | - | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
110 | 124 | | |
111 | | - | |
112 | | - | |
113 | | - | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
114 | 130 | | |
115 | 131 | | |
116 | | - | |
117 | | - | |
118 | | - | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
119 | 135 | | |
120 | | - | |
| 136 | + | |
| 137 | + | |
121 | 138 | | |
122 | | - | |
123 | | - | |
124 | | - | |
125 | | - | |
126 | | - | |
127 | | - | |
| 139 | + | |
| 140 | + | |
128 | 141 | | |
129 | | - | |
| 142 | + | |
| 143 | + | |
130 | 144 | | |
131 | 145 | | |
132 | 146 | | |
133 | 147 | | |
134 | 148 | | |
135 | | - | |
136 | | - | |
137 | | - | |
138 | | - | |
139 | | - | |
140 | | - | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
141 | 152 | | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
171 | | - | |
172 | | - | |
173 | | - | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
174 | 181 | | |
175 | | - | |
176 | | - | |
177 | | - | |
178 | | - | |
179 | | - | |
180 | | - | |
181 | | - | |
182 | | - | |
183 | | - | |
184 | | - | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
185 | 213 | | |
186 | | - | |
| 214 | + | |
187 | 215 | | |
188 | 216 | | |
189 | 217 | | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
190 | 223 | | |
191 | 224 | | |
192 | 225 | | |
| |||
0 commit comments