From 0f656a6ebd798e340aa8e4710e48fe81631a06b3 Mon Sep 17 00:00:00 2001 From: Nikita Bayev Date: Wed, 11 Feb 2026 22:45:05 +0500 Subject: [PATCH 1/2] fix(loader): default shared loader to spinner-only Disable GIF loading by default in shared loader and make GIF mode opt-in via showGif input. Also add maintainer changelog entry with production Lighthouse snapshots and validation commands. --- CHANGELOG.md | 32 +++++++++++++++++++ .../loading-spinner.component.html | 2 +- .../loading-spinner.component.spec.ts | 15 ++++++++- .../loading-spinner.component.ts | 15 ++++++++- 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d91ea4c4..c888ee99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## 2026-02-11 (Loader Follow-up) + +- Branch: `codex/loader-fix-lighthouse-followup` +- Date: `2026-02-11` + +### Summary + +Follow-up fix for the new shared loader behavior and a production Lighthouse snapshot after the latest merged PR. + +### Maintainer Notes + +- Changed shared loading spinner defaults: + - `app-loading-spinner` now uses spinner-only mode by default. + - GIF loading is opt-in via `[showGif]="true"`. + - On GIF load failure, component now keeps spinner visible instead of hiding it. +- Updated unit tests to cover: + - default non-GIF behavior + - delayed GIF behavior when enabled +- Production Lighthouse snapshot (captured on `2026-02-11`): + - `/salaries` mobile: Performance `47`, Accessibility `100`, Best Practices `93`, SEO `93` + - `/salaries` desktop: Performance `99`, Accessibility `100`, Best Practices `100`, SEO `90` + - `/` mobile: Performance `60`, Accessibility `97`, Best Practices `93`, SEO `100` + - `/` desktop: Performance `74`, Accessibility `98`, Best Practices `93`, SEO `100` +- Key perf observation: + - delayed loader GIF still shows ~4.25 MiB potential savings on `/salaries` mobile when enabled + - moving shared loaders to spinner-only by default avoids this regression for route loading states + +### Validation Performed + +- `npx ng test --no-watch --browsers ChromiumNoSandbox --include=src/app/shared/components/loading-spinner/loading-spinner.component.spec.ts` +- `npm run build-prod` + ## 2026-02-11 - PR: [Techinterview-space/frontend#118](https://github.com/Techinterview-space/frontend/pull/118) diff --git a/src/app/shared/components/loading-spinner/loading-spinner.component.html b/src/app/shared/components/loading-spinner/loading-spinner.component.html index 65fb556a..143c425c 100644 --- a/src/app/shared/components/loading-spinner/loading-spinner.component.html +++ b/src/app/shared/components/loading-spinner/loading-spinner.component.html @@ -13,7 +13,7 @@ [src]="loadingUrl" [alt]="loadingAlt" (load)="onGifLoaded()" - (error)="onGifLoaded()" + (error)="onGifLoadFailed()" title="Вертимся как можем и загружаем данные..." /> diff --git a/src/app/shared/components/loading-spinner/loading-spinner.component.spec.ts b/src/app/shared/components/loading-spinner/loading-spinner.component.spec.ts index bb4846cb..ee3303bd 100644 --- a/src/app/shared/components/loading-spinner/loading-spinner.component.spec.ts +++ b/src/app/shared/components/loading-spinner/loading-spinner.component.spec.ts @@ -24,8 +24,21 @@ describe("LoadingSpinnerComponent", () => { expect(component).toBeTruthy(); }); - it("delays gif request until threshold", fakeAsync(() => { + it("does not request gif by default", fakeAsync(() => { component.ngOnDestroy(); + component.showGif = false; + component.loadingUrl = ""; + + component.ngOnInit(); + tick(2000); + expect(component.loadingUrl).toBe(""); + + component.ngOnDestroy(); + })); + + it("delays gif request until threshold when enabled", fakeAsync(() => { + component.ngOnDestroy(); + component.showGif = true; component.delayMs = 500; component.loadingUrl = ""; diff --git a/src/app/shared/components/loading-spinner/loading-spinner.component.ts b/src/app/shared/components/loading-spinner/loading-spinner.component.ts index b7c42f25..6683a47d 100644 --- a/src/app/shared/components/loading-spinner/loading-spinner.component.ts +++ b/src/app/shared/components/loading-spinner/loading-spinner.component.ts @@ -10,6 +10,9 @@ export class LoadingSpinnerComponent implements OnInit, OnDestroy { @Input() style = "spinner-border-lg"; + @Input() + showGif = false; + @Input() delayMs = 750; @@ -24,6 +27,10 @@ export class LoadingSpinnerComponent implements OnInit, OnDestroy { private delayTimerId: ReturnType | null = null; ngOnInit(): void { + if (!this.showGif) { + return; + } + const now = new Date(); const isOdd = now.getHours() % 2 === 1; const selectedGif = isOdd @@ -32,10 +39,11 @@ export class LoadingSpinnerComponent implements OnInit, OnDestroy { const selectedAlt = isOdd ? "Loading cat GIF" : "Loading dog GIF"; // Delay heavy GIF loading so fast responses avoid a multi-MB transfer. + const delay = Math.max(0, this.delayMs); this.delayTimerId = setTimeout(() => { this.loadingUrl = selectedGif; this.loadingAlt = selectedAlt; - }, this.delayMs); + }, delay); } ngOnDestroy(): void { @@ -48,4 +56,9 @@ export class LoadingSpinnerComponent implements OnInit, OnDestroy { onGifLoaded(): void { this.showPreloader = false; } + + onGifLoadFailed(): void { + this.loadingUrl = ""; + this.showPreloader = true; + } } From a79e8d4fef163461828989e54d1ce90341823599 Mon Sep 17 00:00:00 2001 From: Nikita Bayev Date: Wed, 11 Feb 2026 22:47:36 +0500 Subject: [PATCH 2/2] docs(changelog): add PR link for loader follow-up --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c888ee99..5108d988 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 2026-02-11 (Loader Follow-up) +- PR: [Techinterview-space/frontend#119](https://github.com/Techinterview-space/frontend/pull/119) - Branch: `codex/loader-fix-lighthouse-followup` - Date: `2026-02-11`