Understanding Angular Modules

Understanding Angular ModulesA quick but comprehensive guide for understanding the different types of Angular ModulesGiancarlo BuompriscoBlockedUnblockFollowFollowingApr 29Understanding the different types of Angular modules is a key factor for architecting or refactoring an application.

The concept of Angular modules has matured since they were first introduced in the framework in a late RC release.

But as years have passed, both the Angular team and the community have come up with guidelines that explain what the different types of modules are, and what they are for.

Anatomy of an Angular ModuleAngular modules are made of a simple set of properties and one lifecycle hook.

In order to fully understand modules, we want to first inspect each property and what they are for.

Let’s have an overview of the NgModule interface:DeclarationsMaybe the simplest and most used property, we use the declarations array for importing components, directives, and pipes.

ProvidersAnother commonly known property, we use the array providers for defining services that have been decorated with the Injectable decorator, which makes them accessible via the Angular DI.

ImportsWe use the imports array for importing other modules.

ExportsBy default, everything defined in a module is private.

Exports is an array that allows the declarations and the declarations within a module accessible from the modules that import the module where these are defined.

EntryComponentsEntryComponents specifies the list of components compiled when the module is bootstrapped.

These components are not components defined in a template but are normally loaded imperatively, for example using ViewContainerRef.

createComponent().

An example is routing components, but the framework adds them to entryComponents automatically.

BootstrapBootstrap also specifies components compiled when the module is bootstrapped and automatically adds them to entryComponents.

IdA name that identifies the moduleSchemasThe allowed values for this property are NO_ERRORS_SCHEMA or CUSTOM_ELEMENTS_SCHEMA that you may want to use when using, for instance, a web component.

I recommend using this with care, as components that you may have left undefined will not throw an error.

It’s something that can be normally used when testing when you do not want to test components you haven’t defined in the module.

But always use being aware of what is actually being skipped by the compiler.

JITThis property will make the framework always compile the module using JIT rather than AOT.

Before we start diving into each of them, let’s first say that we have 5 different types of modules:Domain ModulesRouted ModulesRouting ModulesService ModulesWidget ModulesTo these, I feel like we need to also mention 3 extra modules: AppModule, AppServerModule, and SharedModule.

AppModuleLet’s start with the most common module you’ll see, the so-called AppModule.

AppModule, also often referred to as the root module, is the module responsible for bootstrapping the whole application, that means we need to import into the AppModule all the modules and providers that are required for running the application.

This module usually imports core Angular modules, shared modules, domain modules, service modules, and AppRoutingModule (the root routing module which we will introduce later).

Also, it bootstraps the root component, usually called AppComponent.

Remember, anything that can be lazy-loaded should not be imported in this module.

That means — if we only need a service contained in a module in a lazy-loaded route, we only import it in that route’s module.

Checklistdeclares and bootstraps only root component (mandatory)imports other modules (Angular modules, domain modules, SharedModule)can declare providersdoesn’t export anythingAppServerModuleAppServerModule is only used if you’re using server-side rendering for your app.

I would have called it the server counterpart of AppModule, but the Angular documentation has probably a better definition for it:It’s the bridge between the Universal server-side renderer and the Angular application.

SharedModuleA SharedModule is a module responsible for hosting all shared entities that will be provided to every module of the application.

A SharedModule is usually made up of entities that are shared across different modules within a project — but aren’t normally needed outside of it.

It’s important to understand what should be built in a SharedModule and what should be built in a library: when you find that services or components can be reused across different teams and projects and that ideally don’t change very often, you may want to build an Angular Library instead than hosting your files locally.

The SharedModule is normally imported by AppModule.

A more in-depth explanation about this can be found in my previous article for creating enterprise-grade project structures.

Domain ModulesDomain modules are module pertaining features of your application.

For instance, e-commerce apps may contain the following domain modules:Shopping cart — that exports shopping-cart.

component.

tsCheck-out that — exports check-out.

component.

tsProduct detail view — that exports product-detail-view.

component.

tsDepending on the complexity of a module, which is up to you to evaluate, a domain module can be broken down into smaller domain modules.

For instance, the Product detail view module could import smaller modules such as product comments, product description, or product reviews.

This does make sense when each module is a complex collection of components, or if you think that in the future a certain component will be more and more complex.

ChecklistDomain modules:only export the top componentrarely declare providerscan be imported by AppModule or other Domain modulesRouting ModulesRouting modules are responsible for declaring the routes of a domain module (including AppModule), passing the configuration to the module, and for defining guards and resolvers services.

This also includes referencing the modules that will load lazy-loaded routes that we will show in the next section.

Let’s see an example of a Routing module for a profile page domain module:Difference between AppRoutingModule and Children Routing Modules:AppRoutingModule will define routes using the forRoot property on RouterModule, while all others should use the property forChild.

As you can see in the example above, we’re using forChildChecklistRouting Modules:import the routing configuration with forRoot or forChildcan declare resolvers and guards as providers — and not any other servicealways export RouterModuledo not declare anythingRouted ModulesRouted modules are very simply defined as the modules hosting a lazy-loaded route, which are referenced by a Routing Module imported by a Domain Module or AppModule.

Let’s see a simple example:We first define a routed module for the lazy-loaded route ProfilePage called ProfilePageModule:And then we reference (rather than import) ProfilePageModule in the module AppRoutingModule:Always make sure the path to your module is correct, and that the name of the module is exactly the same as the one referenced in the path.

Also, watch out for the extension: as you can see in the example above, it’s omitted.

It is, instead, referenced by the relative routing moduleService ModulesAs the name suggests, Service modules are modules that only define services.

Good examples of these are HttpClientModule.

They are normally useful in a variety of situations:only handling logic without any references to UI that leads to highly-reusable pieces of logic that can be used by different domain modulesmessagingstate managementChecklistService modules:only define providersare imported by Domain ModulesWidget ModulesWidgets Modules are modules that collect and export declarations.

An example of WidgetModule is 3rd party UI libraries that provide components and directives.

If you or your company are building a UI library, it can probably be classified as such.

ChecklistWidget modules:only declare declarationsrarely have providersonly export declarationsare imported by Domain ModulesSigns you may need a Widget Module:declarations are highly reusabledeclarations are not specific to any domain modulea component is not a containerFinal WordsAs the community keeps growing and getting more expert at writing Angular applications, I believe it’s still possible that the list of module types can be different or expand in the future.

Even if you do not remember all the rules, ask yourself these questions when writing a module which will help you architect modules according to the guidelines:should this particular component/service be imported?should these declarations be private/public?should these declarations be part of a separate Widget Module?should these services be defined here, or should they live in a Service Module?should this group of components be a smaller domain module?As always, my recommendation is to keep architecture matters a team issue, and not a one-man issue.

By asking and following these questions, you also provide your team with a clear guideline to follow, which should also result in a smooth and consistent way that the whole team can understand and abides by.