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 (
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 the
AppModule. It mainly contains singleton services that are common to the whole application (for instance, an
AuthServicethat allows access to the current user from anywhere in the application), as well as components used only in the
AppComponenttemplate (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”
FeatureModulethat provides access to application administration (only for authorized users). This division into
FeatureModulealso 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. A
FeatureModulecan 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 a
NotificationsModulethat 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
Here, we are defining:
/articlesroute that displays the list of items
/articles/:idroute 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
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.
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.
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 is providing the
AdminGuard to prevent the module from being loaded while the
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.