feat(store-header): add fetchpriority and loading attributes to images for performance optimization

This commit is contained in:
2026-09-22 10:02:53 -03:00
parent 32f86d14d6
commit 1f35a6d709
7 changed files with 81 additions and 17 deletions

View File

@@ -90,6 +90,11 @@ describe('App', () => {
expect(
document.head.querySelector<HTMLLinkElement>('link[rel~="icon"]')?.getAttribute('href'),
).toBe(tenant.favicon);
expect(
document.head
.querySelector<HTMLLinkElement>('link[rel~="icon"]')
?.getAttribute('fetchpriority'),
).toBe('high');
});
it('renders the tenant not found screen when the tenant is missing', async () => {
@@ -114,6 +119,10 @@ describe('App', () => {
expect(
document.head.querySelector<HTMLLinkElement>('link[rel~="icon"]')?.getAttribute('href'),
).toBe("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'/%3E");
expect(
document.head
.querySelector<HTMLLinkElement>('link[rel~="icon"]')
?.getAttribute('fetchpriority'),
).toBe('high');
});
});

View File

@@ -78,6 +78,7 @@ export class App {
}
favicon.setAttribute('href', faviconHref);
favicon.setAttribute('fetchpriority', 'high');
});
}

View File

@@ -1,8 +1,16 @@
<header class="immersive-header" [class.immersive-header--compact]="!showHero()">
<div
class="immersive-header__backdrop"
[style.background-image]="backgroundImageUrl() ? 'url(' + backgroundImageUrl() + ')' : null"
></div>
<div class="immersive-header__backdrop">
@if (showHero() && backgroundImageUrl(); as backgroundImage) {
<img
class="immersive-header__backdrop-image"
[src]="backgroundImage"
alt=""
loading="eager"
fetchpriority="high"
decoding="async"
/>
}
</div>
<div class="immersive-header__content">
<nav
@@ -11,7 +19,13 @@
>
<a routerLink="/" class="immersive-header__brand" aria-label="Ir al inicio">
@if (logoUrl()) {
<img [src]="logoUrl()" alt="Logo del comercio" />
<img
[src]="logoUrl()"
alt="Logo del comercio"
loading="eager"
fetchpriority="high"
decoding="async"
/>
}
</a>

View File

@@ -25,9 +25,19 @@
grid-area: 1 / 1;
position: relative;
z-index: 0;
overflow: hidden;
background-color: #101010;
background-position: center 42%;
background-size: cover;
}
.immersive-header__backdrop-image {
position: absolute;
inset: 0;
z-index: 0;
display: block;
width: 100%;
height: 100%;
object-fit: cover;
object-position: center 42%;
}
.immersive-header__backdrop::before,
@@ -35,6 +45,8 @@
content: '';
position: absolute;
inset: 0;
z-index: 1;
pointer-events: none;
}
.immersive-header__backdrop::before {

View File

@@ -13,7 +13,14 @@
aria-label="Logo del comercio"
>
@if (logoUrl()) {
<img class="store-layout__brand-logo" [src]="logoUrl()" alt="Logo del comercio" />
<img
class="store-layout__brand-logo"
[src]="logoUrl()"
alt="Logo del comercio"
loading="eager"
fetchpriority="high"
decoding="async"
/>
} @else {
<div class="store-layout__brand-logo-shell" aria-hidden="true">
<span class="store-layout__brand-logo-skeleton"></span>

View File

@@ -281,10 +281,27 @@ describe('StoreLayoutComponent', () => {
expect(element.querySelector('.immersive-header__description')?.textContent).toContain(
'Reservá tu entrada',
);
expect(element.querySelectorAll('.continuous-carousel__set')).toHaveLength(2);
expect(element.querySelector('.continuous-carousel__image')?.getAttribute('src')).toBe(
'/first.jpg',
const backdropImage = element.querySelector<HTMLImageElement>(
'.immersive-header__backdrop-image',
);
expect(backdropImage?.getAttribute('src')).toBe(tenant.header_bg_image);
expect(backdropImage?.getAttribute('loading')).toBe('eager');
expect(backdropImage?.getAttribute('fetchpriority')).toBe('high');
expect(backdropImage?.getAttribute('decoding')).toBe('async');
const headerLogo = element.querySelector<HTMLImageElement>('.immersive-header__brand img');
expect(headerLogo?.getAttribute('loading')).toBe('eager');
expect(headerLogo?.getAttribute('fetchpriority')).toBe('high');
expect(headerLogo?.getAttribute('decoding')).toBe('async');
expect(element.querySelectorAll('.continuous-carousel__set')).toHaveLength(2);
const carouselImages = element.querySelectorAll<HTMLImageElement>(
'.continuous-carousel__image',
);
expect(carouselImages[0]?.getAttribute('src')).toBe('/first.jpg');
expect(carouselImages[0]?.getAttribute('loading')).toBe('eager');
expect(carouselImages[0]?.getAttribute('fetchpriority')).toBe('low');
expect(carouselImages[1]?.getAttribute('fetchpriority')).toBe('low');
expect(carouselImages[5]?.getAttribute('loading')).toBe('lazy');
expect(carouselImages[5]?.getAttribute('fetchpriority')).toBe('low');
expect(element.querySelector('app-cart-icon')).not.toBeNull();
});
@@ -487,11 +504,13 @@ describe('StoreLayoutComponent', () => {
expect(compiled.querySelector('[data-testid="store-header-brand-slot"]')).not.toBeNull();
expect(compiled.querySelector('[data-testid="store-footer-brand-slot"]')).not.toBeNull();
expect(
compiled.querySelector(
`app-store-header img.store-layout__brand-logo[src="${tenant.header_logo}"]`,
),
).not.toBeNull();
const headerLogo = compiled.querySelector<HTMLImageElement>(
`app-store-header img.store-layout__brand-logo[src="${tenant.header_logo}"]`,
);
expect(headerLogo).not.toBeNull();
expect(headerLogo?.getAttribute('loading')).toBe('eager');
expect(headerLogo?.getAttribute('fetchpriority')).toBe('high');
expect(headerLogo?.getAttribute('decoding')).toBe('async');
expect(
compiled.querySelector(
`app-store-footer img.store-layout__brand-logo[src="${tenant.footer_logo}"]`,

View File

@@ -9,6 +9,8 @@
[src]="image"
alt=""
[loading]="set === 0 && $index < 5 ? 'eager' : 'lazy'"
fetchpriority="low"
decoding="async"
/>
}
</div>