1

To improve the performance of an Angular 12 SSR web app I would like to preload the hero image on the home page. Currently, we have a link element in our index.html but that preloads the image on every route, not only the home page.

<link rel="preload" as="image" href="https://example.com/assets/img/bg/hero_image.png" />

Additionally, I am lazyloading the path/module

    {
        path: '',
        loadChildren: () => import('./pages/home/home.module').then((m) => m.HomePageModule),
    },

It seems like you can not add an element in the home page template

What options do I have to preload the image as early as possible?

Chris
  • 704
  • 1
  • 11
  • 32
  • Please use either `angular` or `angularjs` in your tags. They're working very differently, and the tag descriptions are clear. –  May 17 '22 at 10:24
  • Thank you, I did not know they were different. Sorry for that – Chris May 17 '22 at 10:27
  • I see I got a close request, please let me know why you believe so. Maybe I can improve my question or perhaps there is something basic I am missing. Thanks in advance – Chris May 17 '22 at 10:29
  • @Chris One way is create blob of image, and save it in assets folder, and assign this blob directly to src of img. – GRD May 17 '22 at 11:14
  • @GRD will that be as effective as calling preload in the head? I will give that a try and compare the performance of the two – Chris May 17 '22 at 11:25

1 Answers1

0

Hope this is helpful to someone trying to achieve the same result as I was in the future.

What I ended up doing is creating a service to inject a preload link element in the head of the document. And then called the services in components where I wanted to add the preloaded inside ngOnInit()

To be able to do this tho I have to pass the components renderer and head to the service as well as the asset for which I created an interface.

The service:

//services/preloader-service/preload.service.ts

import { Injectable, Inject, Renderer2, PLATFORM_ID } from '@angular/core';
import { isPlatformServer } from '@angular/common';
import { PreloadableAsset } from './preloadable-asset.type';

@Injectable({
    providedIn: 'root',
})
export class PreloadService {
    constructor(@Inject(PLATFORM_ID) private platformId: object) {}

    makePreloadable(link: string, as: string, media?: string) {
        if (as === 'image') {
            const type = 'image/' + link.split('.').pop();
            const asset: PreloadableAsset = {
                as,
                href: link,
                type,
                media,
            };
            return asset;
        }
    }

    preloadAsset(renderer: Renderer2, head: HTMLHeadElement, asset: PreloadableAsset) {
        if (isPlatformServer(this.platformId) && asset.href) {
            const preloader = renderer.createElement('link');
            renderer.setAttribute(preloader, 'rel', 'preload');
            renderer.setAttribute(preloader, 'href', asset.href);
            if (asset.as === 'image') {
                renderer.setAttribute(preloader, 'as', asset.as);
                if (asset.type) {
                    renderer.setAttribute(preloader, 'type', asset.type);
                }
                if (asset.media) {
                    renderer.setAttribute(preloader, 'media', asset.media);
                }
            }
            renderer.appendChild(head, preloader);
        }
    }
}

The interface:

export interface PreloadableAsset {
    as?: string;
    type?: string;
    href: string;
    media?: string;
}
Chris
  • 704
  • 1
  • 11
  • 32