on
Angular Modules
While a project is being developed, the more the features are numerous, the more difficult it is to comprehend the code. Angular offers a division through modules, that allows splitting the different features of the application. There is a strong correlation, or even a total equivalence between the different modules of an Angular application and the business features of the project.
The App Module
The main and first module of the application is the AppModule
. Before dividing the application into different modules, the AppModule
holds the entire application. After the division, its role is to import the modules provided by Angular (BrowserModule
, BrowserAnimationsModule
etc.), and then each of the submodules.
There are three types of “sub-modules”:
CoreModule
: it is unique within the application. It must only be imported into theAppModule
. It mainly contains singleton services that are common to the whole application (for instance, anAuthService
that allows access to the current user from anywhere in the application), as well as components used only in theAppComponent
template (for example, the application menu, the navigation bar, etc.)SharedModule
: Also unique within the application, it contains all components that are common to the application. It must not provide any services.FeatureModule
: As its name implies, it is a module specific to a “feature”. In our case, each menu entry is a feature module. We also have an “admin”FeatureModule
that provides access to application administration (only for authorized users). This division intoFeatureModule
also makes it possible to separate the code cleanly in order to have two developers easily work in parallel on different features without having to modify the file app-module.ts. AFeatureModule
can provide services specific to its module, their lifetime will be the same as that of the module. For instance, if your application offers a notifications system, it is appropriate to have aNotificationsModule
that contains the component displaying the notification list, the corresponding service, the notification detail component, and so on.
This summary table makes it possible to quickly know which type of module matches a given situation.
Let’s assume that you have an “articles” module allowing you to list articles, and an “admin” module managing the private area of the application. This is the AppModule
after applying this breakdown:
The routing modules
There is in fact a fourth type of module, which the tutorial proposes to classify in the category of features modules but which we prefer to distinguish for the sake of clarity: the routing modules. These modules only aim to define a set of routes and sub-routes allowing the link between a URL address and the component to be displayed. Moreover, the routing modules provide “guards” regulating access to a route. Here is an example:
This refers to the main routing module of the application, the AppRoutingModule
. In this module, a main route is established, the /login
route accessible to all users. This module also provides the AuthGuard
, which verifies that a user is authenticated.
Let’s analyze now the ArticlesRouting
module, imported by the ArticlesModule
module, the latter having been imported by the AppModule
.
Here, we are defining:
- the
/articles
route that displays the list of items - the
/articles/:id
route that allows you to display the detail of an article
These two routes are only accessible if the user is authenticated, that is if he passes the AuthGuard
provided by the AppRoutingModule
.
Finally, this is the AdminRouting
module that allows defining the routes of the admin panel:
This module defines a single /admin/users
route allowing an authenticated user and administrator to access the list of users.
The AdminGuard
is provided in the AdminRoutingModule
since it is only used in the context of this module.
Make sure you are using imports: [RouterModule.forChild(routes)]
and not imports: [RouterModule.forRoot(routes)]
in all the application’s feature modules. A call to forRoot
in a child component, as well as lazy-loaded, can cause an error at execution.
Lazy Loading
In some cases, it is not necessary to load the entire application at startup. For example, a non-admin user will never have access to the admin panel of the application. Therefore, he will never need to use the Admin module. To avoid this useless import, you can use the lazy load so that it is loaded only when it is actually needed.
For each module you wish to lazy load, you just have to define the route associated with the module in the routing app. Let’s assume that we want to load the Admin module while keeping the Article module eager loaded. Here’s what the AppRoutingModule
becomes:
AdminRoutingModule
becomes:
Now the AppRoutingModule
is providing the AdminGuard
to prevent the module from being loaded while the AuthGuard
and AdminGuard
have prevented access to that route. In addition, the AdminModule
is no longer imported into the AppModule
. It is therefore only loaded when accessing the /admin/users
route as a logged in user and administrator.
Make sure you do not overuse the lazy load. If the loading time of the first page of a typical user is reduced, an administrator will have to wait a little longer (the time that the module loads) to access the Admin panel. A balance must be struck between the use of the module and the loading time at start-up.