[Fuente: https://angular.io/guide/lazy-loading-ngmodules]
Lazy Loading Feature Modules
——– PREVIOUS start——-
Feature Modules
Feature modules are NgModules for the purpose of organizing code.
As your app grows, you can organize code relevant for a specific feature. This helps apply clear boundaries for features. With feature modules, you can keep code related to a specific functionality or feature separate from other code. Delineating areas of your app helps with collaboration between developers and teams, separating directives, and managing the size of the root module.
Feature modules vs. root modules
A feature module is an organizational best practice, as opposed to a concept of the core Angular API. A feature module delivers a cohesive set of functionality focused on a specific application need such as a user workflow, routing, or forms. While you can do everything within the root module, feature modules help you partition the app into focused areas. A feature module collaborates with the root module and with other modules through the services it provides and the components, directives, and pipes that it shares.
Types of Feature Modules
There are five general categories of feature modules which tend to fall into the following groups:
- Domain feature modules.
- Routed feature modules.
- Routing modules.
- Service feature modules.
- Widget feature modules.
While the following guidelines describe the use of each type and their typical characteristics, in real world apps, you may see hybrids.
Domain feature modules
- Domain feature modules deliver a user experience dedicated to a particular application domain like editing a customer or placing an order.
- They typically have a top component that acts as the feature root and private, supporting sub-components descend from it.
- Domain feature modules consist mostly of declarations. Only the top component is exported.
- Domain feature modules rarely have providers. When they do, the lifetime of the provided services should be the same as the lifetime of the module.
- Domain feature modules are typically imported exactly once by a larger feature module.
- They might be imported by the root
AppModule
of a small application that lacks routing.
Routed feature modules
- Routed feature modules are domain feature modules whose top components are the targets of router navigation routes.
- All lazy-loaded modules are routed feature modules by definition.
- Routed feature modules don’t export anything because their components never appear in the template of an external component.
- A lazy-loaded routed feature module should not be imported by any module. Doing so would trigger an eager load, defeating the purpose of lazy loading.That means you won’t see them mentioned among the
AppModule
imports. An eager loaded routed feature module must be imported by another module so that the compiler learns about its components. - Routed feature modules rarely have providers for reasons explained in Lazy Loading Feature Modules. When they do, the lifetime of the provided services should be the same as the lifetime of the module. Don’t provide application-wide singleton services in a routed feature module or in a module that the routed module imports.
Routing modules
A routing module provides routing configuration for another module and separates routing concerns from its companion module.
A routing module typically does the following:
- Defines routes.
- Adds router configuration to the module’s imports.
- Adds guard and resolver service providers to the module’s providers.
- The name of the routing module should parallel the name of its companion module, using the suffix “Routing”. For example,
FooModule
infoo.module.ts
has a routing module namedFooRoutingModule
infoo-routing.module.ts
. If the companion module is the rootAppModule
, theAppRoutingModule
adds router configuration to its imports withRouterModule.forRoot(routes)
. All other routing modules are children that importRouterModule.forChild(routes)
. - A routing module re-exports the
RouterModule as a convenience so that components of the companion module have access to router directives such as
RouterLink and
RouterOutlet.
- A routing module does not have its own declarations. Components, directives, and pipes are the responsibility of the feature module, not the routing module.
A routing module should only be imported by its companion module.
Service feature modules
Service modules provide utility services such as data access and messaging. Ideally, they consist entirely of providers and have no declarations. Angular’s HttpClientModule is a good example of a service module.
The root AppModule
is the only module that should import service modules.
Widget feature modules
- A widget module makes components, directives, and pipes available to external modules. Many third-party UI component libraries are widget modules.
- A widget module should consist entirely of declarations, most of them exported.
- A widget module should rarely have providers.
- Import widget modules in any module whose component templates need the widgets.
——– PREVIOUS end——-
Prerequisites
A basic understanding of the following:
- Feature Modules.
- JavaScript Modules vs. NgModules.
- Frequently Used Modules.
- Types of Feature Modules.
- Routing and Navigation.
For the final sample app with two lazy loaded modules that this page describes, see the live example / download example.
High level view
There are three main steps to setting up a lazy loaded feature module:
- Create the feature module.
- Create the feature module’s routing module.
- Configure the routes.
Set up an app
If you don’t already have an app, you can follow the steps below to create one with the CLI. If you do already have an app, skip to Configure the routes. Enter the following command where customer-app
is the name of your app:
ng new customer-app --routing
This creates an app called customer-app
and the --routing
flag generates a file called app-routing.module.ts
, which is one of the files you need for setting up lazy loading for your feature module. Navigate into the project by issuing the command cd customer-app
.
Create a feature module with routing
Next, you’ll need a feature module to route to. To make one, enter the following command at the terminal window prompt where customers
is the name of the module:
ng generate module customers --routing
This creates a customers folder with two files inside; CustomersModule
and CustomersRoutingModule
. CustomersModule
will act as the gatekeeper for anything that concerns customers. CustomersRoutingModule
will handle any customer-related routing. This keeps the app’s structure organized as the app grows and allows you to reuse this module while easily keeping its routing intact.
The CLI imports the CustomersRoutingModule
into the CustomersModule
by adding a JavaScript import statement at the top of the file and adding CustomersRoutingModule
to the @
NgModule imports array.
Add a component to the feature module
In order to see the module being lazy loaded in the browser, create a component to render some HTML when the app loads CustomersModule
. At the command line, enter the following:
ng generate component customers/customer-list
This creates a folder inside of customers
called customer-list
with the four files that make up the component.
Just like with the routing module, the CLI imports the CustomerListComponent
into the CustomersModule
.
Add another feature module
For another place to route to, create a second feature module with routing:
ng generate module orders --routing
This makes a new folder called orders
containing an OrdersModule
and an OrdersRoutingModule
.
Now, just like with the CustomersModule
, give it some content:
ng generate component orders/order-list
Set up the UI
Though you can type the URL into the address bar, a nav is easier for the user and more common. Replace the default placeholder markup in app.component.html
with a custom nav so you can easily navigate to your modules in the browser:
<h1> {{title}} </h1> <button routerLink="/customers">Customers</button> <button routerLink="/orders">Orders</button> <button routerLink="">Home</button> <router-outlet></router-outlet>
To make the buttons work, you need to configure the routing modules.
Configure the routes
The two feature modules, OrdersModule
and CustomersModule
, have to be wired up to the AppRoutingModule
so the router knows about them. The structure is as follows:
Each feature module acts as a doorway via the router. In the AppRoutingModule
, you configure the routes to the feature modules, in this case OrdersModule
and CustomersModule
. This way, the router knows to go to the feature module. The feature module then connects the AppRoutingModule
to the CustomersRoutingModule
or the OrdersRoutingModule
. Those routing modules tell the router where to go to load relevant components.
Routes at the app level
In AppRoutingModule
, update the routes
array with the following:
const routes: Routes = [ { path: 'customers', loadChildren: './customers/customers.module#CustomersModule' }, { path: 'orders', loadChildren: './orders/orders.module#OrdersModule' }, { path: '', redirectTo: '', pathMatch: 'full' } ];
The import statements stay the same. The first two paths are the routes to the CustomersModule
and the OrdersModule
respectively. Notice that the lazy loading syntax uses loadChildren followed by a string that is the relative path to the module, a hash mark or
#
, and the module’s class name.
Inside the feature module
Next, take a look at customers.module.ts
. If you’re using the CLI and following the steps outlined in this page, you don’t have to do anything here. The feature module is like a connector between the AppRoutingModule
and the feature routing module. The AppRoutingModule
imports the feature module, CustomersModule
, and CustomersModule
in turn imports the CustomersRoutingModule
.
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { CustomersRoutingModule } from './customers-routing.module'; import { CustomerListComponent } from './customer-list/customer-list.component'; @NgModule({ imports: [ CommonModule, CustomersRoutingModule ], declarations: [CustomerListComponent] }) export class CustomersModule { }
The customers.module.ts
file imports the CustomersRoutingModule
and CustomerListComponent
so the CustomersModule
class can have access to them. CustomersRoutingModule
is then listed in the @
NgModule imports array giving
CustomersModule
access to its own routing module, and CustomerListComponent
is in the declarations array, which means
CustomerListComponent
belongs to the CustomersModule
.
Configure the feature module’s routes
The next step is in customers-routing.module.ts
. First, import the component at the top of the file with the other JavaScript import statements. Then, add the route to CustomerListComponent
.
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { CustomerListComponent } from './customer-list/customer-list.component'; const routes: Routes = [ { path: '', component: CustomerListComponent } ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class CustomersRoutingModule { }
Notice that the path
is set to an empty string. This is because the path in AppRoutingModule
is already set to customers
, so this route in the CustomersRoutingModule
, is already within the customers
context. Every route in this routing module is a child route.
Repeat this last step of importing the OrdersListComponent
and configuring the Routes array for the orders-routing.module.ts
:
import { OrderListComponent } from './order-list/order-list.component'; const routes: Routes = [ { path: '', component: OrderListComponent } ];
Now, if you view the app in the browser, the three buttons take you to each module.
Confirm it’s working
You can check to see that a module is indeed being lazy loaded with the Chrome developer tools. In Chrome, open the dev tools by pressing Cmd+Option+i
on a Mac or Ctrl+Alt+i
on a PC and go to the Network Tab.
Click on the Orders or Customers button. If you see a chunk appear, you’ve wired everything up properly and the feature module is being lazy loaded. A chunk should appear for Orders and for Customers but will only appear once for each.
forRoot() and
forChild()
You might have noticed that the CLI adds RouterModule.forRoot(routes)
to the app-routing.module.ts
imports array. This lets Angular know that this module,
AppRoutingModule
, is a routing module and forRoot() specifies that this is the root routing module. It configures all the routes you pass to it, gives you access to the router directives, and registers the
RouterService
. Use forRoot() in the
AppRoutingModule
—that is, one time in the app at the root level.
The CLI also adds RouterModule.forChild(routes)
to feature routing modules. This way, Angular knows that the route list is only responsible for providing additional routes and is intended for feature modules. You can use forChild() in multiple modules.
forRoot() contains injector configuration which is global; such as configuring the Router.
forChild() has no injector configuration, only directives such as
RouterOutlet and
RouterLink.