Closed gorkemyontem closed 6 years ago
Thanks for a great question!
Just to be clear, just because we return null does not mean we don't render anything, the img
-tag will still be in the template.
<img [src]="defaultImage" [lazyLoad]="image" alt="my image description" title="my image title">
window
-object so ng-lazyload-image
will leave the img
-tag as it is (<img src="path-to-default-image.jpg" [lazyLoad]="image" alt="my image description" title="my image title">
)alt
and title
attribute (correct me if I am wrong).So, I do not think SEO will be a problem as long as you:
[src]
instead of [defaultImage]
alt
and title
Or have I missed something (SEO is not my strongest suit)?
+1
The image will have class "ng-failed-lazyloaded" on server-side when using AngularUniversal/SSR. I'm guessing an exception is being thrown due to window object/etc not being available in node.
I don't think it's a major SEO concern because alt/title will work. However, the actual .jpg/.png path won't be indexed. So, if you're hoping for your images to be found on images.google.com, they won't be. (or at least not on search engines that don't understand javascript). Also, a lot of social media sites will take a screenshot of the site when creating a post & they don't understand javascript.
Regardless of SEO, I think it'd be nice from a user standpoint to see the images start loading while waiting for the full angular app to load in the background. (in case of heavy download to get full angular app running due to poor AOT/treeShaking/etc)
The trick is to determine which images to load server-side. Without window object available in node & without knowing the user's screen size I don't see how you could calculate if it'll be in the initial viewport or not. It should probably be up to the consuming app programmer to understand their own layout & determine which images to eager load on SSR. Maybe something like [EagerLoadOnSSR]="true" or [EagerLoadOnSSR]="false" ?
Another option would be to have a global config to enable/disable eager load for SSR. The problem with this is that the browser will have already downloaded all images before being replaced by full angular app, so why would the full app keep lazy load enabled? I think it could still be beneficial for "virtual scrolling" apps where SSR only has 1 page of results but actual app can scroll infinitely.
@gorkemyontem
For now I'm using this workaround:
import { Directive, ElementRef, Input, OnChanges } from '@angular/core';
import {Utils} from "../services/utils";
@Directive({
selector: '[ssrImageSrc]'
})
export class ssrImageSrcDirective implements OnChanges {
@Input('ssrImageSrc') imageSrc: string;
ngOnChanges(changes: Object): void {
this.updateImageSrc();
}
private updateImageSrc(): void {
if (Utils.IsAngularUniversal) {
(<any>this.element.nativeElement).src = this.imageSrc;
}
}
constructor(private element: ElementRef) {
this.updateImageSrc();
}
}
Utils.IsAngularUniversal is my own method to determine if I'm in SSR mode. You could swap it with Angular's built-in method isPlatformServer from @angular/common.
I'm using it like this:
<img [lazyLoad]="imageUrl" [ssrImageSrc]="imageUrl" />
It's essentially the same as this, but I assumed it'd fail because [src] and [lazyLoad] would fight each other (i didn't test it this way, so I could be wrong):
<img [lazyLoad]="imageUrl" [src]="Utils.IsAngularUniversal ? imageUrl : undefined" />
Hi @tjoskar and @speige, Thanks for the answers. I have tried both of the solutions but the result was not what I was expecting. But this is because maybe I am expecting something impossible.
Either I use [src]="defaultImage"
or [src]="Utils.IsAngularUniversal ? imageUrl : undefined"
it adds src on the server side. This is the behavior that I am looking for.
However, When I inspect the Network activity on Google Chrome DevTools, I see that, when the page is loaded on the server side, the images are also loaded. And whenever the client part is loaded, the images load again with the behavior of lazy loading.
Since the point of using lazy load is to reduce request number and size, doing it on server side doesn't seem like a good idea.
Hi @gorkemyontem,
But this is because maybe I am expecting something impossible.
What are you expecting? 😉
If the server returns src="..."
the browser will start to load the image and there is nothing we can do on the client side to stop it (as far as I know). But you want to load the defaultImage
, right?
Or do you mean that the defaultImage
is loaded twice?
Let's say you have the following template:
<img [src]="'path-to-default-image.jpg'" [lazyLoad]="'path-to-image1.jpg'">
// some other content so you have to scroll to see the next image
<img [src]="'path-to-default-image.jpg'" [lazyLoad]="'path-to-image2.jpg'">
I expect the following to happens:
The server returns the following template
<img src="path-to-default-image.jpg" ...>
// some other content so you have to scroll to see the next image
<img src="path-to-default-image.jpg" ...>
The browser parse the html code and loades path-to-default-image.jpg (once)
ng-lazyload-image
kicks in but sice you are not using [defaultImage]
it will not do anything.
ng-lazyload-image
sets src
to path-to-image1.jpg
and loads it once
Is that not what is happening?
Closing this due to inactivity. Please let me know if the problem still occurs.
The library works great and does the job. However, on the server side it just put an empty img tag.
<img />
The reason of this expected behavior is this code:
Although Google can now get to js, there are some controversies about this too. For instance: https://blog.seoprofiler.com/googles-john-mueller-lazy-loading-images-work-google/
Back in PHP time, in one of my own lazy loading implementation, I had used
What is your stand on this? I'd like to contribute with an pull request if you share my concerns.