Advanced Angular: Performance & Enterprise State

Viewport & Interaction Deferrals

Alex Okrushko
NgRx, Angular GDE
Advanced Angular: Performance & Enterprise State

Lesson Description

The "Viewport & Interaction Deferrals" Lesson is part of the full, Advanced Angular: Performance & Enterprise State course featured in this preview video. Here's what you'd learn in this lesson:

Alex discusses deferring non-critical content to optimize page load, demonstrating lazy-loading a venue map and using viewport triggers for incremental hydration and performance improvements.

Preview

Transcript from the "Viewport & Interaction Deferrals" Lesson

[00:00:00]
>> Alex Okrushko: Next we're going to do is we can start deferring certain things from the view, so in my event details page. Event details page. Right now, that's the event details page, I don't have the venue map, for example, let me just add this venue map, but we don't want to see this venue map immediately loading because we kind of push it a little bit behind, like below the fold.

[00:00:36]
So our app will look a little bit like this, maybe right, so we're just going to push it a little below the fold. So it's not critically necessary on the initial load, but once user starts scrolling further down, then we're going to load this, so we don't slow down the initial load. Let's add that. So I'm going to be a little bit of copy pasting because again, this is just a lot of the Tailwind stuff, but I'm going to slow down and see what exactly I need to actually focus on here, so we have our event details, we have our left content side and we have the right content side.

[00:01:29]
So on the left content side, see this left side. That is this one, we're going to push the venue map on that side as well right now. So in my left side, I'm going to be pasting this one. All right. And if I save. Should. Did I miss something top bottom. Right, didn't save yet, so let me just probably extra div, yes, extra div, always extra div.

[00:02:12]
Ah, so now this would be. And you see they have check venue details below, that is down there, let me start my local dev server and server. So I can see it. Here our events and then. Once I go here. They say I don't have it, and then it's there like CC below, so it's basically below the fold. Now we need to do a few things here and let's see what we're doing here.

[00:02:58]
So other than some divs and images and everything else, this is our image of the venue, by the way, we can make it optimized as well right away, let's see what's the size for this. What's the size for this, an event? This is 500 by 600, so we can just do this as well right away, just say, hey, my width is 500 and 600.

[00:03:35]
And let it let it do its thing. Do we need priority? We do not need priority, and G and now she doesn't know what the NG source is, so we do need to add NG optimized here. Optimized image. No one knows what it is. So we have this in NG optimized image, and we'll hydrate this on viewport. What does it mean? So we can defer the loading, and we can do, for example, on viewport, we'll delay this once the viewport is there, but we can include this, but only start hydrating this, which is adding JavaScript functionality to it, only when it gets into the viewport for hydrate to work.

[00:04:25]
There's a few requirements. This is basically incremental hydration. Initially we'll just hydrate the whole thing. But here we say defer this and do not hydrate it until the viewport, it comes to the viewport. For this to work. Just event replay is not good enough. When we do provide client hydration, we need to do with incremental hydration.

[00:05:02]
And incremental hydration does the event replay as well, by default, so, but it also allows to increment the hydration here. So you can hydrate things on specific triggers. What are those triggers? There are many. There's on viewport, there's a bunch of them. On immediate, on some timeout. The best way to show this is actually go defer and Angular would provide the whole list of things that it can differ on.

[00:05:48]
For yes, here you go, so you can do on idle, right, once your app starts loading and you're just sitting, it's like, then it'll use the resources to download, so it's like proactively on viewport, once you get something in viewport interaction we're going to use as well once you start interacting something on hover, right, so maybe you want to hydrate some functionality, not when you click, which is interaction, but once you just hover over that click button.

[00:06:18]
They'll start, they'll start fetching immediately, or hydrating immediately, otherwise it just won't do anything, immediate and timer, so there's multiple triggers. So we're going to do hydrate on viewport. OK, hydrate on viewport, with incremental hydration, the only, the other caveat, in the dev server. We have hot module replacement.

[00:06:49]
Which again works great for a lot of things, but incremental hydration is kind of conflicting with this. So it basically disables incremental hydration if you do not, if you have hot modular replacement, so. What we need to do is also let me see, I think I had instructions here as well, yes, so when you serve no HMR but basically not hot no hot module replacement.

[00:07:27]
Then it'll help with the hydration. All right. One more thing I want to show you before I do the demo. Right now our hydration here. The viewport, it does, it is basically using some standard divs, right, standard divs and images. So there's not a lot to hydrate here. We can do even better, just for demonstration purposes, you don't have to change this.

[00:07:54]
I just want for the demonstration purposes. I mean, actually, let me just serve first here and then I'll show you something else as well, so now we're having the serving the application with no HMR so we can see the incremental hydration. Let's get back to the page. This is our page. We're going to reload the page.

[00:08:29]
And let's see something here, a network. See, there's no request for any venue yet. I'll start slowly getting in. Boom. I see a request for the venue. So once it got to the viewport, only then that piece of code got hydrated, and it basically requested the image. So again, it helps on the initial page load if you have longer pages for stuff before, below the fold.

[00:09:04]
Like specifically here. One more thing I want to show you here is, let's just extract this to some component. Let's just create a component, you don't have to do it, I'm just showing this for the demo purposes, so we have this venue map. Yes, right, so we'll create the component. Component that will have selector of app, this is our prefix and venue map, OK, so this is our venue map, this is, it does need a NG optimized image.

[00:09:58]
Optimized image and we'll have the template for this, the one that we just copied. And this is the export class venue map, for example. OK, very simple component, just for demo purposes. Now in this placeholder, I'm going to use this app venue map, and I can self close this as well, it needs to be imported, it's already imported here as well automatically.

[00:10:32]
And NG optimized image, we can also optimize. Yeah, the image there. This guy here, and I'll do it in a second. So now we have this chunk, that is, could be loaded separately, because it's in the deferred block, it's not just some HTML, it's actually another component. Let's see. Here and you can see it is complaining about the optimized, let's see, yeah, just to give us a warning.

[00:11:14]
But you can see at this chunk is now also the lazy chunk. So we have lazy load by routing and we also have lazy load by components within, right, this is really powerful. Let's see what's happening here now, so I'm going to refresh this page. See the page loading. Right, and we don't have anything else, I'm going to clear it, so it's super obvious what's happening here, now I'm going to go into this, getting into the viewport.

[00:12:00]
So we have 2 things happen. We loaded this chunk. Which is our venue map. And then the venue map itself loaded the image, right? This is super powerful. So you can optimize your page and hydrate as we go. One more thing I wanted to show you. Once we have incremental hydration and incremental hydration. Angular will provide us with additional tools.

[00:12:36]
And you might see it here, says show hydration overlays. So let's do that. So right now in our app, see that. Water, like, so it basically says that, let's just refresh it. Initially not hydrated, it refreshes this as well, and then it starts basically hydrating everything here, so initially it loads and then it starts hydrating.

[00:13:13]
Hydrating parts, so all of this is hydrated, we start scrolling below, boom, this. This map first appears and then the hydration icon appears, so it loads that chunk and hydrates it when it gets in the viewport. So again, this is some nice things you can do. Let's try something, I just see and then viewport. What if we do one however, maybe you can get it to work.

[00:14:01]
Let's see if that would get there, that's to see the. Just to prove the point, let's see if we can get there to work. So, let's see. Right now. Network OK, let's see our hydration overlay. Show hydration overlay. And alright, still see it appeared not hydrated yet. So if I hover over it, now it attached JavaScript to it.

[00:14:24]
So it loaded because we're getting into the viewport. It loaded the image as well, but then only hydrated after, so it prefetched proactively and hydrated only once a day before that, it was just just regular DOM. Nothing in the component itself, I mean our component doesn't do much, it's not functional really, but if it had any functionality, clicks, whatever, none of it would have been listening for that until it's hydrated.

[00:15:09]
But because we also have the event replay that I mentioned before, it will still, once I hydrate, if I did click on something, it will push those events into that component. All right, that's, let's just do this on viewport again. Viewport is even better, right, so don't even see it. Last thing here. This is, this is more to add to functionality as well, so we all have, I have a click button here for the buy tickets, let's just wrap it with another defer.

[00:15:58]
And this is the clickable elements. This is the interaction, it's called interaction deferral. So we can hydrate. Hydrate on interaction direction. Right, so. And we'll wrap all this button. So it will hydrate on the direction, it has the placeholder as well. Meaning that before it hydrates that we can have something and in our case we'll just have the same button but just no click events so we'll attach the click events only when we start interacting with that button.

[00:17:02]
Can do that as well, so let's do that. This ng-optimized image, well, I'm just going to add NG here as well, NG source. I'm going to add the height and width. What's the height and width for this? Let's check height and width. 26 by 200. It's fine. So width. Let's do 200. 100 that should be working fine. And this will be priority because it's in the initial page load as well, so just added this event, so I'm going to basically optimize all the images now.

[00:18:02]
Cool, so this buy ticket is not hydrated until I click on this, once I click, it quickly attaches the functionality to it, and now it's functional as well. OK. Let's, by the way, let's just do the final build for this. Npm build. I'm going to serve again. This serve our Node. It's soar here go. Express server listening.

[00:18:31]
I'm going to do this event itself because it's pre-rendered. All right, let's check. What the performance for this page now is. This is local codes 400 new report. Analyze page, this is not a homepage, this is the one that we would just had some deferred hydration on. Yeah, that's what I expect. There you go. Cannot beat 100, cannot beat 100.

[00:18:57]
And you can see it's quite happy below above all the things we optimize our images, look at this, 0.7 seconds, LCP which is just phenomenal, and you can see the viewport immediately available, and what it does is just the only thing is like there's some critical path here, that's the only complaint that I had, look at this.

[00:19:30]
And again, the time to live for some of the caches this could be longer, which is fine. And there's just no compression applied, that's fine, we're not. Yeah, that's fine. That's really cool, really cool, cannot beat 100. And then again, boom, all of this we have heavy image here, that is still optimized, still large enough, but always optimized.

[00:20:02]
Perfect, so now you know how to do all the optimizations and how SSR can really help, how we can even take it further, we can lazy load by routes, we can lazy load by components, and we can moreover, we can hydrate and delay the functionality of those components only until certain points as well. Really, really, really, really powerful stuff.

[00:20:25]
Questions anywhere around some of these things, is it clear? Who's excited, who's excited to start optimizing their apps? Yes, yes. I have a question. If most of our controllers are sending information to the API via the body of posts, is it possible to do anything with that, with that route configuration, or do you have to refactor those to contain everything in the path of the route?

[00:21:00]
So, let me repeat so I understand that. So most of your controllers, right, you say basically your components are sending the API requests via post to get the data, post body to get the data, that should be fine anyway, because when it pre-renders that page, for example, right, it would do what the app would do anyway, so if it goes, that's why.

[00:21:34]
It's a good point. Look at this. So if I stop my server. My backend. And let me do the build. It's building. It pre-rendered, and now let me just serve this. So I'm serving my backend application. But look at this. If I just refresh this page. Event not found. Right. If I'm not found, so it basically knows that it's not there when, but when it was rendering, it's not there.

[00:22:07]
Same thing here, right, it just doesn't have any information. Right, so. It basically does what your app would typically do just on the server-side. There are certain things that server-side components won't be able to do. They will have no access to window objects, DOM itself, right, so if your components, that's another good point, by the way, if your components have anything like DOM updates and manually you do, there's a way to do it, it's called, for example, in my details here.

[00:22:45]
If I had, I don't know, some element here, I can grab the view from here and update native element with something, you can do this, but you have to do it in the constructor, and there's a special hook is called after next render. So this would be ignored, whatever you do here is ignored by server-side. But it will be applied on the client-side or component when it hydrates it.

[00:22:50]
So then it can do some manipulation here, there's after next render and then there's after every render, every render is, every time this component is re-rendered, it will call this. Good question.

Learn Straight from the Experts Who Shape the Modern Web

  • 250+
    In-depth Courses
  • Industry Leading Experts
  • 24
    Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now