Feature Module
|
Guidelines
|
Domain
|
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.
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.
Don't provide application-wide singleton services in a domain feature 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.
~~~ {.l-sub-section}
For an example, see the [Make _Contact_ a feature module](guide/ngmodule)
section of the [NgModules](guide/ngmodule) page, before routing is introduced.
~~~
|
Routed
|
_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.
This page's `ContactModule`, `HeroModule`, and `CrisisModule` are routed feature modules.
Routed feature modules _shouldn't export anything_.
They don't have to 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.
`HeroModule` and `CrisisModule` are lazy loaded. They aren't mentioned among the `AppModule` imports.
But an eager loaded routed feature module must be imported by another module
so that the compiler learns about its components.
`ContactModule` is eager loaded and therefore listed among the `AppModule` imports.
Routed Feature Modules rarely have _providers_ for reasons [explained earlier](guide/ngmodule-faq#q-why-bad).
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
|
A [routing module](guide/router) *provides routing configuration* for another module.
A routing module separates routing concerns from its companion module.
A routing module typically does the following:
* Defines routes.
* Adds router configuration to the module's `imports`.
* Re-exports `RouterModule`.
* 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` in `foo.module.ts` has a routing module named `FooRoutingModule`
in `foo-routing.module.ts`
If the companion module is the _root_ `AppModule`,
the `AppRoutingModule` adds router configuration to its `imports` with `RouterModule.forRoot(routes)`.
All other routing modules are children that import `RouterModule.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 *should 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.
The `AppRoutingModule`, `ContactRoutingModule`, and `HeroRoutingModule` are good examples.
~~~ {.l-sub-section}
See also [Do you need a _Routing Module_?](guide/router) on the
[Routing & Navigation](guide/router) page.
~~~
|
Service
|
Service modules *provide utility services* such as data access and messaging.
Ideally, they consist entirely of _providers_ and have no _declarations_.
The `CoreModule` and Angular's `HttpModule` are good examples.
Service Modules should _only_ be imported by the root `AppModule`.
Do *not* import service modules in other feature modules.
If you deviate from this guideline, know what you're doing and why.
|
Widget
|
A widget module makes *components, directives, and pipes* available to external modules.
`CommonModule` and `SharedModule` are widget 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_.
If you deviate from this guideline, know what you're doing and why.
Import widget modules in any module whose component templates need the widgets.
|
The following table summarizes the key characteristics of each _feature module_ group.
~~~ {.l-sub-section}
Real-world modules are often hybrids that knowingly deviate from these guidelines.
~~~
Property
|
Description
|
declarations
|
A list of [declarable](guide/ngmodule-faq#q-declarable) classes,
the *component*, *directive*, and *pipe* classes that _belong to this module_.
These declared classes are visible within the module but invisible to
components in a different module unless they are _exported_ from this module and
the other module _imports_ this one.
Components, directives, and pipes must belong to _exactly_ one module.
The compiler emits an error if you try to declare the same class in more than one module.
*Do not re-declare a class imported from another module.*
|
providers
|
A list of dependency-injection providers.
Angular registers these providers with the root injector of the module's execution context.
That's the application's root injector for all modules loaded when the application starts.
Angular can inject one of these provider services into any component in the application.
If this module or any module loaded at launch provides the `HeroService`,
Angular can inject the same `HeroService` intance into any app component.
A lazy-loaded module has its own sub-root injector which typically
is a direct child of the application root injector.
Lazy-loaded services are scoped to the lazy module's injector.
If a lazy-loaded module also provides the `HeroService`,
any component created within that module's context (such as by router navigation)
gets the local instance of the service, not the instance in the root application injector.
Components in external modules continue to receive the instance created for the application root.
|
imports
|
A list of supporting modules.
Specifically, the list of modules whose exported components, directives, or pipes
are referenced by the component templates declared in this module.
A component template can [reference](guide/ngmodule-faq#q-template-reference) another component, directive, or pipe
when the referenced class is declared in this module
or the class was imported from another module.
A component can use the `NgIf` and `NgFor` directives only because its parent module
imported the Angular `CommonModule` (perhaps indirectly by importing `BrowserModule`).
You can import many standard directives with the `CommonModule`
but some familiar directives belong to other modules.
A component template can bind with `[(ngModel)]` only after importing the Angular `FormsModule`.
|
exports
|
A list of declarations—*component*, *directive*, and *pipe* classes—that
an importing module can use.
Exported declarations are the module's _public API_.
A component in another module can [reference](guide/ngmodule-faq#q-template-reference) _this_ module's `HeroComponent`
if it imports this module and this module exports `HeroComponent`.
Declarations are private by default.
If this module does _not_ export `HeroComponent`, no other module can see it.
Importing a module does _not_ automatically re-export the imported module's imports.
Module 'B' can't use `ngIf` just because it imported module `A` which imported `CommonModule`.
Module 'B' must import `CommonModule` itself.
A module can list another module among its `exports`, in which case
all of that module's public components, directives, and pipes are exported.
[Re-export](guide/ngmodule-faq#q-re-export) makes module transitivity explicit.
If Module 'A' re-exports `CommonModule` and Module 'B' imports Module 'A',
Module 'B' components can use `ngIf` even though 'B' itself didn't import `CommonModule`.
|
bootstrap
|
A list of components that can be bootstrapped.
Usually there's only one component in this list, the _root component_ of the application.
Angular can launch with multiple bootstrap components,
each with its own location in the host web page.
A bootstrap component is automatically an `entryComponent`.
|
entryComponents
|
A list of components that are _not_ [referenced](guide/ngmodule-faq#q-template-reference) in a reachable component template.
Most developers never set this property.
The [Angular compiler](guide/ngmodule-faq#q-angular-compiler) must know about every component actually used in the application.
The compiler can discover most components by walking the tree of references
from one component template to another.
But there's always at least one component that's not referenced in any template:
the root component, `AppComponent`, that you bootstrap to launch the app.
That's why it's called an _entry component_.
Routed components are also _entry components_ because they aren't referenced in a template either.
The router creates them and drops them into the DOM near a ``.
While the bootstrapped and routed components are _entry components_,
you usually don't have to add them to a module's `entryComponents` list.
Angular automatically adds components in the module's `bootstrap` list to the `entryComponents` list.
The `RouterModule` adds routed components to that list.
That leaves only the following sources of undiscoverable components:
* Components bootstrapped using one of the imperative techniques.
* Components dynamically loaded into the DOM by some means other than the router.
Both are advanced techniques that few developers ever employ.
If you are one of those few, you must add these components to the
`entryComponents` list yourself, either programmatically or by hand.
|