Video details

Haim Agami-Turjeman - Lazy loading single components on demand | Angular UP 2021


Lazy loading single components on demand "We often load components to our apps that our users use rarely in their day-to-day interaction with our app. We will see how to leverage Angular ComponentFactory to dynamically load these components and throw in JS natural import() method to make them even lazy-loaded, only when they are needed while making our app load faster and feel more responsive.


Hi everybody. This is also my first time. A bit excited, but I'm fine. So my name is JAIM. I work at Yelp for the past two years. We are doing mostly Angular and she said to me to do that. Yeah. Okay, so this is it. This is my son and he started picking up English lately and I expected from him to say that, what is a cat? What is a dog? How do you say it in English? And instead he's asking me what is Angular? What do you say? Lazy all the time. What is component? And it's a bit scary, but okay, we did this too, I guess most of us. So again, this is what I'm saying. Why did he pick up all these words? Because for the past year or so, we are concentrated in Yachtpo to take our application to the next level. And one of this is to make them faster, to make them more responsive to our users. And we moved to Angular from AngularJS and we tried to stay cutting edge as much as we can. And I guess all of you know, you get to a lot of issues with bundle size and feature requests that made your application get slower and slower. So let's look at an example. When we started the new product, the screen looked like this with a few text boxes and a few buttons and everything was great. And after a while we got the new feature request. Hey guys, please add me up an emoji picker to our text boxes. It will be great for our users. They really love that. And who is here is an optimistic developer. Yeah, everybody. I'm the King of the optimistics. And of course, no problem. Piece of game. I guess you know that by heart. So we added a picker model to our module. We added the component to the HTML and you know what? It was actually a piece of cake. So Voila, we had an emoji picker. Piece of cake. As we said, after a few weeks, again, another feature request. Please add a tag picker to our textbook. Says it will be great. I don't have to say the next line. We seem to love cake very much. So you understand that something is wrong here. Something we need to do. Something about these small features that are entered to our page all the time. And we want to give the user the best experience they can. Lots of people. Yeah, sorry. We had the merged picker, of course, and Voila tag picker. Great. You probably understand that from being this fancy car and fast car, it's not immediately, but over time, move to look like this. The boxes here are on purpose. This is the small feature that we get all the time. So we're here to talk about what can be done about that. Maybe most of you already doing that. That's great. But if you're not, then it's good that you're here. So first thing first. Let's make our component dynamically loaded runtime. Okay. We now start to parse the template and wants to know what he wants to compile. So we need at first at least get it out of the template. So we need to dynamically load that component. So for that we have the component factory Resolver and the component factory itself. We can get it from the constructor and component resolve a component factory. I think I have some errors on that. Yeah. And then we have a view container ref. It's like some kind of an anchor in our page. We clear the container so there's no other component there. And then we add the component using the create component method on the view container ref. This is great. This is what we wanted, but it's not the old solution because it's not lazy loaded like that. And most of our problem is lazy Loading this stuff. Yeah. So lazy is another word that my son already understands, but what is failed to understand why it's a good thing. I'm saying to everybody, hey, let's lazy load that. And he's saying that why are you so enthusiastic about lazy? So yeah, lazy is energy efficient in our case. And before the next slide, before Angular IV, the compiler needed the template to understand the compiled context. So the components was inherently tied to a module and we couldn't do anything about it. And this is just an example for what was we needed the Ng module factory loader to load our module. And this is a special feature of Angular at that time. And we load the module, we get the entry component module instance and from that we get the component factory like we saw before for the next method. So this is already been deprecated from Angular Nine and we'll get it in a minute. And then came Ivy Ivy. Angular Nine was introduced a few weeks ago and I don't know which of you still, I mean, most of you I guess are Angular Nine and above. And Angular Ivy came and started a journey for us to be able to create standalone components. It changed the way the compiler looked at the templates and understand the context. So basically we don't need modules anymore. It's not still the case and at least not in Angular 13. It will be in the future. But Angular team didn't say when, but they are working on it and this gave us the ability to ditch the model Loading part of the whole scenario. So from Angular Nine, Ng model factory loader was deprecated. It's still there. You can still use it if you are nine, but it's deprecated and you can see that now. We just need the Resolver. We can inject it from the constructor and then using JavaScript native import method, we can just import the component itself. When it's resolved, we can use the component factory Resolver and a component factory. So to create a component inside one of our encores that we defined, which is a view container. Okay, so this is Post IV. This is Angular R Nine and Angler 13 was released a few days ago and there was a lot of changes. But for this change, for this matter, they only updated the API of the create component. And now you see, we don't need even the component Resolver factory. We don't even need a component factory. Angular takes care of this on its own. And we straight given the component one component, the type of the component that we want to create. The journey from being mostly dependent on module to then being dependent on a component factory. And now this is gone. It's not gone, it's behind the scenes. I guess Angular wants to remove it entirely and they just give us in steps the ability to remove it at all from our code base. And this is all the journey to standalone components. Yeah, well, I can use that. You can have a map of types, you can have square brackets with the name this is given a TypeScript compiler will not give you an error because it understands it's inside the import and it knows to read this into this and you get this, but it's simply JavaScript handling because it's not there in the compile time. Okay, I had errors for that. Okay, let's see that in action. So first, yeah, this is a not lazy sample. Okay, you see, it's not lazy and we can see that the module let me enlarge that is 100 kilo and it depends on Angular material on purpose to get some meat into it. And when I click on my other son and a single component, you can see that it's already loaded to the browser and no lazy loaded magic happens. So if we get back to the code, this is my template of the page. So you can see the app component one and the upload component are there. And as I say, the compiler understand that he needs that from the module. And if I didn't put it here, then it will say, hey, I don't know this component. What are you doing? Okay, so this is the case. And of course I needed to do that. I needed to. Wow. I don't see anything. I needed to import it and declare it in a specific way. Okay, so let's see what can be done. This is a lazy version. We can get an ng container with some reference. There's a lot of ways to do that specifically, but this is one of them. And then we get it as a view container rest as we saw in the slides, and we get the component factory Resolver and we import it and then use it clear. And another thing that I didn't show in Slides is that you can add the injector to it, which allows you to use some injection tokens or maybe modules that you loaded inside the loaded components. For instance, I created the injection token project name and I provided it in this feature module. I call it Angular app and you can see in the component that I use the project name after I injected it in the constructor. So giving the create component the method, the injector allows the component to enter the injection tree of all the application and use what is available for it. So let me compile it on purpose. It wasn't running before I compile it. I want to show you that you can see the IntelliJ telling me that something is wrong. Some small component is not declared in any angular module. Okay, we can live with that. Okay. I didn't declare it anywhere. And we can see already that webpack is smart enough to make bundles calling to the import statement. So this is the two features models and I have the small component and the large component and you can see already that the sizes of the models change. So let's do it here. So now we have the module which is 300 kilo. And when I load the single component, I get a small bundle, of course. And this is the depends on the material. So I get another 400K. You can imagine that if you use some niche components in your page, like I showed you with the Emoji Speaker, this can save you a few hundred of K in Loading time. And in some cases it's crucial. And if you have a lot of this, it's even more crucial. Of course. Okay, I have 30 minutes. Apparently, before I finish, I want to show you another option to use that. Another method that can be used for this scenario is the render component. Okay. It's Theta render component. I just so it will be English. Okay, so you can use the render component and same as the create component. Give it the component type and it gets JSON object of all kinds of options. One of them is what is the host? I just call it anchor. I can say Hi and of course the injector. And you can see that in the page. I had the anchor. I of course can call it hiim. It doesn't matter. Of course, for this to work we need to add no error schema to the module, but it's working the same way. Yeah, really? Combined. Great. And I just saw we also use the injector again. So you see high Angular app and the component is lazy loaded by itself and that's it. One small thing, a bit of a cheat, I admit. In the large component you saw that I used the angular material. So what I did to enable the Angular material in my component is just create a model for it and import the models I needed for the specific component. I guess that for summary before, I guess something for summary use that ability. Angular is taking us through there step by step. We're not there yet, but we will be there, I hope next year and I guess one of the problems or one of the hard difficulties for the Angular team that many frameworks that we use to use the module system and to break it apart or to change it, it will be a slow process so I guess we still need the models for the time being but I showed you some methods to avoid it or use it in a better or smarter way that you can use in your application and you can build a lot of services around it. For instance, you can build a service that with some kind of Rick JS pushes what is the component and the other components? Listen to what component to render. Now there are a lot of samples in the internet and you can play around with it. It's really cool and it's really helpful for your application so that's it. Thank you very much. I'm Jaime I'm from Yelp as I said.