Skip to content

VSB-TUO/Cherry-pick: Fix home-page SSR->CSR flicker#1288

Merged
milanmajchrak merged 5 commits into
customer/vsb-tuofrom
vsb-tuo/fe-fix-home-page-flicker
May 20, 2026
Merged

VSB-TUO/Cherry-pick: Fix home-page SSR->CSR flicker#1288
milanmajchrak merged 5 commits into
customer/vsb-tuofrom
vsb-tuo/fe-fix-home-page-flicker

Conversation

@Kasinhou
Copy link
Copy Markdown

Problem description

Cherry-pick from #1287

Sync verification

If en.json5 or cs.json5 translation files were updated:

  • Run yarn run sync-i18n -t src/assets/i18n/cs.json5 -i to synchronize messages, and changes are included in this PR.

Manual Testing (if applicable)

Copilot review

  • Requested review from Copilot

jm 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.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 once ApplicationRef.isStable emits true.
  • Re-enables eager-loading of the custom theme 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.

Comment thread src/themes/eager-themes.module.ts
Comment thread src/index.html
Comment thread src/app/app.component.spec.ts
@milanmajchrak milanmajchrak changed the title Vsb-tuo/Cherry-pick: Fix home-page SSR->CSR flicker VSB-TUO/Cherry-pick: Fix home-page SSR->CSR flicker May 20, 2026
@milanmajchrak milanmajchrak merged commit 5ed10f1 into customer/vsb-tuo May 20, 2026
2 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants