At a high level, you configure a parent route pointing to each feature module in your root module.
Then, inside of each feature module, you associate child routes with components you want to render when the module is loaded.
To stay on track, we’ll move on to a basic example, but for more about how the Angular router works, here’s a great post from Nate Lapinski, a writer for Angular In Depth.
Sample Project with Eager Loaded ModulesYou can find the code I will be referencing in the ng-lazy-loading-demo repo on Github.
In the master branch, you will find a CLI generated Angular app with a few added components.
If you install the dependencies and run it, you will find a basic home page with some nav links at the top for a “Products” view and “Profile” view.
Lazy loading has not been implemented yet, but let’s take a closer look so we can see how the architecture changes when it is implemented.
First, let’s take a look at the file structure.
As you will see in the image below, three modules have been generated in the app folder, a core module and two feature modules.
The core module contains two components, the nav component and the home component, while the profile module contains the profile component and the product module contains the product component.
All three modules are exporting the components they contain.
Next, let’s take a look at the app.
ts file to find out how our components are loaded.
As we can see in the gist below, the HomeComponent, NavComponent, ProductComponent, and the ProfileComponent are all imported and included in the declarations array, which means that they will all be loaded when the app initializes.
In other words, they are all eager loaded — the opposite of lazy loaded.
Let’s also take a look at the app-routing.
ts file so that we understand how the router state is defined based on the path, determining which component is rendered.
As shown in the gist below, we have three URLs defined — these make up the router state configuration.
This is how the Angular router is able to associate a URL with a component.
When navigation occurs, the Angular router compares the URL with the path defined in the router state configuration.
When it finds a matching URL, it renders the component associated with it.
For example, navigating to http://localhost:4200/product renders the product component.
Finally, let’s run the project, open the Chrome Dev Tools, click on the network tab, and refresh the page.
Notice that 17 requests were made to the server.
If you navigate to either the product page or the profile page, you will notice that no more requests are made because the modules containing those components were already eager loaded and packaged up with the main bundle.
Sample Project with Lazy Loaded ModulesNow, if we checkout the feature/lazy_loaded branch, run it, open the network tab of the Chrome Dev Tools, and refresh the page we will see the same number of requests to load the page.
Because the product module is lazy loaded, we can observe in the GIF below that the product-product-module.
js packet is loaded in response to another request when we navigate to the products page.
The same occurs when navigating to the profile page.
So what changes were made to our app in thefeature/lazy_loaded branch to lazy load the product and profile modules?First, let’s take a look at the app.
ts file below.
Notice that theProductComponent and theProfileComponent are no longer imported into the root module or included in the declarations array.
This is because we do not want our app to load them until it needs them.
If they were imported here, the product and profile modules and their components and services would be loaded when our app initializes no mater what we do.
Next, let’s take a look at the app-routing.
ts file below.
You will find that the route configurations have changed.
Instead of associating the URL with a component to render, the URL is associated with a module to load.
The route configurations in the gist above are generally referred to as parent routes.
As previously mentioned, the Angular router looks for a route configuration that matches the URL, then loads the associated feature module.
Each feature module will have its own route configurations, which are referred to as child routes, and are generally defined in a file namedmoduleName-routing.
ts by convention.
Let’s look at an example.
If we run the app and navigate to http://localhost:4200/profile, the Angular router will search for matches in the app-routing.
ts file and find the following route configuration, associating it with the profile module.
When the profile module is loaded, the router will compare the URL with the child route configurations defined in the profile-routing.
It understands that these are child routes because when the instance of the RouterModule is created and imported, it passes the routes array into the .
As you can see in the gist below, there is only one route configuration, but we could define as many as needed here.
Since there is nothing in the URL after ‘profile’, the router matches it with the empty child route in the gist above.
This route configuration may look much more familiar to you, as the URL is associated with the ProfileComponent, which will be rendered when the module is finished loading.
ConclusionIn conclusion, lazy loading is one way for developers to decrease the TTI, improve the user experience, and reduce the bounce rate of their applications.
There are 3 things I hope you can take away from this post:As Deborah Kurata so concisely articulated it in her talk from Ng-Conf 2017, there are three things you need to do in order to implement lazy loading in your application: use feature modules, group routes under a single parent, and do not import the feature modules into any other module.
Lazy loading does not decrease the overall size of your app; it decreases the number of packets, or chunks, that must be loaded before the initial page becomes usable.
Your entire application is still retrieved from the server before it is initially rendered and stored in the browser cache; however, Lazy loaded modules are not loaded initially.
When they are needed, the browser makes a request to the browser cache to retrieve them when they are needed.