From 3253b297eb29a14bd91e4738da5f23a11d273726 Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Fri, 24 Jul 2026 08:28:00 +0400 Subject: [PATCH] docs: add PERFORMANCE_REPORT.md for RC PERF-01 Consolidates the 3 perf-audit commits (reactivity/change-detection, bundles/lazy-loading/tree-shaking, assets) into one report: headline 1.47MB->1.12MB initial bundle (-24%), plus per-area findings and a remaining-work list (primeng/primeicons still in package.json pending a blocked npm uninstall, large lazy chunks, combineLatest sites). Co-Authored-By: Claude Sonnet 5 --- docs/PERFORMANCE_REPORT.md | 55 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 docs/PERFORMANCE_REPORT.md diff --git a/docs/PERFORMANCE_REPORT.md b/docs/PERFORMANCE_REPORT.md new file mode 100644 index 0000000..6a5055e --- /dev/null +++ b/docs/PERFORMANCE_REPORT.md @@ -0,0 +1,55 @@ +# Performance Report — RC PERF-01 + +Production-readiness performance audit + fixes, application-wide. No redesign, no UI/visual changes, no route/API changes — pure performance/correctness work. Three sequential commits on branch `B2B` (not pushed): + +| Commit | Scope | +|---|---| +| `61a5714` | Angular reactivity, change detection, rendering, memory | +| `4bf0666` | Bundles, lazy-loading, tree-shaking, large chunks | +| `2e931bb` | Assets: images, fonts, SVG, CSS | + +`npm run build` verified green after every commit. `npx tsc --noEmit` clean throughout. + +## Headline result + +Initial bundle: **1.47 MB → 1.12 MB raw** (−350 KB / −24%), transfer estimate **263.59 kB → 221.51 kB** (−16%). Budget overage shrank from 769 KB over to 417 KB over (still a warning, not an error — the 700 KB budget itself is unchanged and still exceeded, see Remaining below). Global CSS bundle: 9.60 kB → 8.41 kB raw (−12%). + +## Findings and fixes by area + +### Angular reactivity / change detection / memory (`61a5714`) + +- **`.subscribe()` audit**: 149 call sites across 44 files. Spot-checked every long-lived stream in the highest-risk components (route params, router events, polling/intervals) — all already use `takeUntilDestroyed(this.destroyRef)` or an explicit `Subscription` + `ngOnDestroy` unsubscribe. One-shot HTTP-backed subscribes self-complete, no leak. **No leaks found** — the codebase's existing discipline here was already solid. +- **`ChangeDetectionStrategy.OnPush`**: 191 components, 190 already had it. Added to the 1 remaining (`app.ts`, the root component) — verified safe (signal-driven template, no direct DOM mutation). +- **`@for`/`track`**: fully compliant app-wide — the codebase is entirely on the new control-flow syntax, which the compiler requires `track` on, so there was nothing to fix. Legacy `*ngFor` without `trackBy`: zero occurrences. +- **Duplicate HTTP calls**: `CategoryFacade` and `ConfigService` already cache via `shareReplay({bufferSize:1, refCount:true})`, applied consistently — no duplicate-request pattern found. +- **Flagged, not fixed**: 2 `combineLatest` sites (`catalog-container.component.ts`, `subcategories.component.ts`) are narrow, already-minimal RxJS composition — converting to `computed()` would touch adjoining facade state shape, judged out of this pass's risk budget. Per-item template method calls in `@for` loops (`getDiscountedPrice`, `itemName`, `categoryName`, `stockLabelKey`) are cheap pure lookups on an already-OnPush host — flagged as pipe-conversion candidates for a future pass, not urgent. + +### Bundles / lazy-loading / tree-shaking (`4bf0666`) + +- **Lazy-loading boundaries**: already correct — every storefront/builder/backoffice route in `app.routes.ts` uses `loadComponent`, nothing eagerly imported. +- **i18n eager-loading — the biggest single win**: `TranslateService` statically imported all three locale packs (ru/en/hy, 346 KB raw combined) into the initial bundle regardless of visitor language. Fixed: `ru` (default) stays eager, `en`/`hy` are now `import()`ed on demand via a new `preloadLanguage()`, awaited inside `languageGuard` before route activation — router blocks navigation until the pack resolves, so there's no untranslated-flash risk. +- **Dead code**: `knip` found `src/app/components/items-carousel/*` (3 files) completely unreferenced anywhere, and the sole consumer of the `primeng` dependency. Deleted the component and its now-dead `primeicons.css` import from `src/styles.scss`. +- **Tree-shaking**: fixed one accidental barrel import in `widget-host.service.ts` (now imports `UnknownWidgetComponent` directly instead of through the `widgets/ui` barrel) — negligible measured impact, but correct going forward. `@lucide/angular` icons already use named tree-shakeable imports. +- **Duplicate deps**: `npm ls` confirms a single deduped `rxjs@7.8.2` — no duplicate module instances. +- **Flagged, not fixed**: `primeng`/`primeicons` remain in `package.json`/lockfile — `npm install`/`uninstall` fails in this environment (`ETARGET`) on a pre-existing, unrelated broken `barry-cache` devDependency, so the lockfile couldn't be safely regenerated by hand. **Follow-up needed**: fix the `barry-cache` devDependency resolution, then `npm uninstall primeng primeicons` to drop the dependency entirely (the code reference is already gone). Large chunks (`project-editor` 320 kB, `catalog-container` 126 kB, `product-details-container` 88 kB, `cart` 61 kB) unchanged — no mechanical split found inside their scope; a real reduction here would mean lazy-loading a sub-feature (e.g. an embedded editor), which is a larger, dedicated task. + +### Assets: images, fonts, SVG, CSS (`2e931bb`) + +- **Images**: storefront `` tags already have `loading="lazy"`/`decoding="async"` on grids/galleries and CLS is already handled via CSS `aspect-ratio` (from prior RC-Visual-02/RC-Premium-01 passes) — nothing to fix. Flagged: a handful of single-image admin/editor previews lack `loading="lazy"` (page-editor, brand-overview, asset-details-drawer) — negligible traffic, left alone. +- **Fonts**: `index.html` already preconnects to Google Fonts, loads DM Sans 400/500/600/700 with `display=swap`; all 4 loaded weights are actually used. Flagged: weights 800/900 are referenced in some component SCSS but never loaded (pre-existing faux-bold rendering) — changing loaded weights risks a visible text difference, left out of scope for a perf-only pass. +- **SVG**: icon system is fully centralized through `@lucide/angular` via `icon-registry.ts` — no inline path duplication. `public/` SVGs checked for editor cruft (metadata/inkscape artifacts) — already clean. Flagged: 5 branding SVGs (`mastercard-logo.min.svg`, `dexar-logo*.svg`, `dexar-favicon.svg`, `novo-logo.svg`, `novo-favicon.svg`) appear unreferenced in `src`, left in place — may back tenant branding resolved from the backend at runtime, deletion needs a human decision, not this pass's call. +- **CSS**: manual grep-based cross-check (literal + hyphen-safe, checked for dynamic `[class.x]`/string-built classes too) of `src/styles.scss` utility classes against all templates. Confirmed-dead and removed: `.btn-primary`/`.btn-secondary`+hover, `.catalog-product-card`, `.item-badges-overlay`, `.item-simple-desc`, `.text-center`, `.mt-1..4`, `.mb-1..4`, `.p-1..4`. + +## Remaining recommendations (not applied — flagged for follow-up) + +1. **`primeng`/`primeicons` still in `package.json`** despite the only consumer being deleted — needs the pre-existing `barry-cache` devDependency resolution issue fixed first, then a clean `npm uninstall`. Highest-value remaining action: would likely close most of the remaining 417 KB budget overage in one move once confirmed. +2. **Large lazy chunks** (`project-editor` 320 kB, `catalog-container` 126 kB) — no mechanical fix found; needs a dedicated task to identify a genuinely lazy-loadable sub-feature inside each. +3. **2 `combineLatest` sites** — safe to leave, candidates for a `computed()` conversion in a future facade-focused pass. +4. **Per-item template method calls** in `@for` loops — pipe-conversion candidates, not urgent (already bounded by OnPush). +5. **Font weights 800/900** used in SCSS but not loaded — either load them explicitly or normalize the SCSS to a loaded weight; a design-system call, not a perf call. +6. **5 unreferenced branding SVGs** — confirm with backend/tenant-branding owner before deleting. +7. **Admin/editor preview images** missing `loading="lazy"` — low priority, low traffic. + +## Verification + +`tsc --noEmit` and `npm run build` run and green after each of the three commits. No live browser session available this session — real-world Core Web Vitals (LCP/CLS/INP) were not measured; recommend a Lighthouse/WebPageTest pass against a deployed build before the client demo referenced in `docs/FRONTEND-ROADMAP.md`.