VSB-TUO/Cherry-pick: Fix home-page SSR->CSR flicker#1288
Merged
milanmajchrak merged 5 commits intoMay 20, 2026
Conversation
added 4 commits
May 19, 2026 14:06
Angular 15 has no provideClientHydration; on every browser load Angular
tears down the entire SSR DOM and rebuilds the component tree from scratch.
Measured CLS = 0.89 at t=1.76s on /home (PerformanceObserver on dev-5).
The visible flicker is that ~600ms rebuild window between SSR view and
populated CSR view.
Two compounding causes, addressed in this PR:
1. CustomEagerThemeModule was commented out in src/themes/eager-themes.module.ts,
so every custom-themed wrapper (footer, header, root, ...) was lazy-loaded via
webpack code-splitting on the browser, stretching the gap. Re-enable it
(the existing custom/eager-theme.module.ts already declares the right set).
Bumps initial bundle by ~256KB; angular.json budget raised from 5MB to 8MB
to accommodate.
2. The bigger cause - no hydration - is masked by an inline pre-bootstrap script
in src/index.html that:
- Captures all <style ng-transition="dspace-angular"> blocks into
<style data-dspace-ssr-keep> tags Angular won't strip (Angular removes
the originals on bootstrap, which is why a naive overlay renders
unstyled).
- Moves (not clones) the SSR-rendered <ds-app> children into an
absolute-positioned overlay so they keep every live DOM/style detail.
- Hides the now-empty <ds-app> via a data-attribute and CSS rule.
- Exposes window.__dspaceRemoveSsrOverlay() for AppComponent to call
once ApplicationRef.isStable fires (with one rAF + 50ms pad).
- 15s safety fallback in case isStable never fires.
Bots and no-JS users still get the original SSR <ds-app> (the overlay is
JS-added). Real users see continuous SSR-rendered content while CSR rebuilds
invisibly underneath, then a 150ms fade reveals the CSR DOM in its final
data-loaded state.
Verified locally via Service Worker that suppresses the removal: overlay's
header height is 80px (proper styling preserved) versus 698px (the unstyled
fallback before this fix's style-preservation step).
Includes a small Windows cmd deploy helper at scripts/dspace-deploy.bat and
matching skill doc at .claude/skills/dspace-deploy/SKILL.md - multi-instance
safe local dev stack via the existing docker compose files.
- angular.json: tighten budget back to 5.5MB warn / 6MB error (was 8MB) - index.html: re-entrancy guard on __dspaceRemoveSsrOverlay (null the pointer up-front so the isStable + 15s safety fallback can't double-fade) - index.html: drop aria-hidden from overlay so screen-reader users get the SSR snapshot during boot (ds-app underneath has visibility:hidden which already excludes it from a11y tree) - index.html: console.warn on the overlay-script catch so a silently broken flicker fix is at least diagnosable in DevTools - typings.d.ts: typed Window.__dspaceRemoveSsrOverlay augmentation; drop the `as any` cast in AppComponent.removeSsrOverlayWhenStable - app.component.spec.ts: cover removeSsrOverlayWhenStable (calls the global once on isStable=true; no-op when global absent) - Drop scripts/dspace-deploy.bat + .claude/skills/dspace-deploy/SKILL.md from this PR per request (local dev tooling, will live elsewhere)
The overlay holds the SSR-rendered children alongside <ds-app>'s CSR-rendered children during the masking window. Cypress's cy.get(selector) sees both copies, so unique-id selectors return 2 elements and cy.click() fails. The overlay is purely a UX smoothing layer (no behaviour to E2E-validate), so short-circuit when window.Cypress is present. Browser users are unaffected.
There was a problem hiding this comment.
Pull request overview
Cherry-picks a fix intended to reduce the visible SSR→CSR “flash/flicker” on /home in this Angular 15 + Universal app by keeping SSR-rendered content visible until the client app stabilizes.
Changes:
- Adds an inline “SSR overlay” bootstrap script + styles in
index.html, and removes the overlay onceApplicationRef.isStableemitstrue. - Re-enables eager-loading of the
customtheme wrappers to avoid lazy-load gaps during client bootstrap. - Updates typings/tests to support and validate the overlay-removal hook; adjusts Angular bundle budgets and ignores local tooling artifacts.
Reviewed changes
Copilot reviewed 5 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/typings.d.ts |
Adds a Window typing for the overlay removal global function. |
src/themes/eager-themes.module.ts |
Includes CustomEagerThemeModule to avoid theme-wrapper lazy-load gaps during bootstrap. |
src/index.html |
Adds SSR-overlay CSS + inline pre-bootstrap script to mask SSR→CSR rebuild flicker. |
src/app/app.component.ts |
Calls the overlay removal global once Angular reaches first stable state. |
src/app/app.component.spec.ts |
Adds unit tests around overlay removal timing/guard behavior. |
angular.json |
Raises initial bundle size budgets to accommodate eager theme loading. |
.gitignore |
Ignores local deploy script artifacts and Playwright investigation outputs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem description
Cherry-pick from #1287
Sync verification
If en.json5 or cs.json5 translation files were updated:
yarn run sync-i18n -t src/assets/i18n/cs.json5 -ito synchronize messages, and changes are included in this PR.Manual Testing (if applicable)
Copilot review