Angular Suite Module¶
A Suite Module aims to solve a determined problem within an application. The module might be tied to a use-case, or a feature. Or it may be purely a set of tools, like the ones of the Suite Framework.
In the case of an application, a Suite Module will most likely be tied to a domain or sub-domain.
Despite of the module's purpose, the project structure is the same. A Suite Module is basically a folder (also referred to as a grouping-folder) decomposed into multiple projects, which we call "libraries" (the term library comes from NX workspaces).
It's worth mentioning that all the schematics and linting are possible thanks to the use of NX Workspaces for Monorepos.
In order to avoid confusion, when the docs mention Angular Modules we refer to
Suite Modules written for the frontend using the Angular framework, contrary to
the concept of Modules used by Angular (or NgModules
) for defining and
grouping related functionalities, configuration, providers, etc. These two terms
(Angular Modules and Suite Modules) will be used interchangeably through this
docs.
Tip
Think of these libraries as the equivalent of a .csproj in a VisualStudio solution. It is the minimum unit that another library or application can reference.
These libraries provides the modules with clear boundaries, this is quite similar to the "Clean Architecture".
Module scope¶
Domain modules¶
Each Suite Module must have a clear scope (enforced by using an NX library tag). Other Suite Modules (with different scopes) will be able to consume only what each Module's root library exposes.
For example, iInspector could have two Suite Modules aptly named Inspections (domain module for managing templates, inspections, items, etc) and Settings (domain module for managing setting definitions, levels, values, etc).
Shared modules¶
In addition to Domain Suite Modules, each application would most likely benefit from having one or more Shared Suite Modules, which would include members that are used/required for fulfilling more than one use case, but at the same time are specific enough for them to not be part of the Suite Shared members.
Libraries¶
This section describes the types of libraries each Angular Suite Module will be comprised. More than one library of each type can be included on a single Module.
Types of libraries¶
-
root: Are groping libraries that take care of importing and re exporting libraries members for consumption for other Suite Modules.
those grouping libraries contain the rest of the libraries, and the exports are defined in the
api/public-api.ts
file.This also implies that one Suite Module domain library could import symbols from another Suite Module root library, which in turn belong to the second Suite Module feature library (only if the module has a shared tag).
-
feature: Feature libraries include mostly smart components (page components, smart wrappers, states management, etc). This type of module:
- will connect the domain facades with the UI components to fully solve a particular use-case or provide a feature.
- will often provide and orchestrate top level page components and
navigation by using
RouterModule.ForChild
. - will often be lazy loaded by the main application module based on its "domain route".
-
ui: UI libraries include dumb components with a certain degree of business logic (i.e. form validation).
-
domain: Domain libraries contain:
- State management logic using NGRX.
- HttpClients for backend communication.
-
shared: Shared libraries, for a Suite Module, include:
- Mostly business case agnostic members (pipes, utility functions, etc). However they should be pretty thin and instead said members should be moved to a shared library instead. Shared libraries are also the place to define environment specific injection tokens.
- All the interfaces and classes required for implementing all the Suite Module features.
Important: "utils" and "domain/entities" libraries are deprecated.
Library boundaries¶
In order to guarantee that each library can be reused when required and that they actually respect their boundaries, NX linting is applied according to the following rules within their Module scope:
- Feature libraries can only depend on UI, Domain, Entities, and Util libraries (in order for Feature components to access state facades).
- UI libraries can only depend on other UI libraries, Entities and Util libraries (allowing for UI composition and for dumb components to reference the Module ViewModels).
- Domain libraries can only depend on Entities and Util libraries. In theory, according to DDD Bounded contexts domains shouldn't cross reference themselves. However, it could be valid to relax this boundary where it would benefit sub domain decomposition.
- Entity libraries can only depend on Util libraries.
- Util libraries can only depend on Util libraries.
- Root libraries can potentially depend on any other type of library, except other Root libraries. The fact that this type of library can expose other libraries members doesn't mean they should be used to do so.
Publishable libraries¶
In some cases, your application might need to make available some of its symbols
over an npm
package. In this case, you should create a publishable library
using for example nx g lib --publishable MinervaLib
, and then import into its
public_api.ts
all symbols from each of your Suite Modules root libraries.
Its important to remark that the other libraries imported have to be buildable too, because those are added to the dependencies list of the library.
secondary entry points are also available, but you have to take care about:
- The library needs to be
buildable
. - Should be created inside the library root folder.
- Its not required to import and re export the libraries in the
public-api.ts
file of the publishable library.
Buildable suite modules¶
The suite module libraries are not buildable by default, but you can use the
buildable
parameter to generate buildable modules.
This could be useful in case you want to export a group of suite modules in a single library.
Its important to remark that this modules are going to be builded only if are
part of a library with a build target defined in the architects option
(commonly created when using the buildable
or publishable
property of nx
libraries schematics).
Example¶
The following image is an example of how a Suite Domain Module, in this case for the Specification domain of MPM, could be divided according to the aforementioned library types and their boundaries. Red lines describe the allowed library imports, while dotted black lines represent library members dependencies.
Notice
It's not shown on the diagram in order to preserve clarity, but root libraries can potentially import symbols from any other library type within the same Suite Module