Declarables are the class types—components, directives, and pipes—that
you can add to a module's declarations list.
They're the only classes that you can add to declarations.
Perhaps you declared "x" in an application sub-module but forgot to export it?
The "x" class isn't visible to other modules until you add it to the exports list.
This always means importing CommonModule from @angular/common for access to
the Angular directives such as NgIf and NgFor.
You can import it directly or from another module that re-exports it.
BrowserModule also re-exports CommonModule from @angular/common,
which means that components in the AppModule module also have access to
the Angular directives every app needs, such as NgIf and NgFor.
Do not importBrowserModule in any other module.
Feature modules and lazy-loaded modules should import CommonModule instead.
They need the common directives. They don't need to re-install the app-wide providers.
如果你在惰性加载模块中导入BrowserModule,Angular就会抛出一个错误。
BrowserModule throws an error if you try to lazy load a module that imports it.
That's not a problem. When three modules all import Module 'A',
Angular evaluates Module 'A' once, the first time it encounters it, and doesn't do so again.
That's true at whatever level A appears in a hierarchy of imported modules.
When Module 'B' imports Module 'A', Module 'C' imports 'B', and Module 'D' imports [C, B, A],
then 'D' triggers the evaluation of 'C', which triggers the evaluation of 'B', which evaluates 'A'.
When Angular gets to the 'B' and 'A' in 'D', they're already cached and ready to go.
Export declarable classes that components in other modules
are able to reference in their templates. These are your public classes.
If you don't export a class, it stays private, visible only to other component
declared in this module.
你可以导出任何可声明类(组件、指令和管道),而不用管它是声明在当前模块中还是某个导入的模块中。
You can export any declarable class—components, directives, and pipes—whether
it's declared in this module or in an imported module.
You can re-export entire imported modules, which effectively re-exports all of their exported classes.
A module can even export a module that it doesn't import.
Private components, directives, and pipes that you need only within components declared in this module.
If you don't want another module to see it, don't export it.
不可声明的对象,比如服务、函数、配置、实体模型等。
Non-declarable objects such as services, functions, configurations, and entity models.
那些只被路由器或引导函数动态加载的组件。
Components that are only loaded dynamically by the router or by bootstrapping.
Such entry components can never be selected in another component's template.
While there's no harm in exporting them, there's also no benefit.
Pure service modules that don't have public (exported) declarations.
For example, there's no point in re-exporting HttpModule because it doesn't export anything.
It's only purpose is to add http service providers to the application as a whole.
我可以重新导出类和模块吗?
Can I re-export classes and modules?
毫无疑问!
Absolutely.
模块是从其它模块中选取类并把它们重新导出成统一、便利的新模块的最佳方式。
Modules are a great way to selectively aggregate classes from other modules and
re-export them in a consolidated, convenience module.
A module can re-export entire modules, which effectively re-exports all of their exported classes.
Angular's own BrowserModule exports a couple of modules like this:
exports:[CommonModule,ApplicationModule]
模块还能导出一个组合,它可以包含自己的声明、某些导入的类以及导入的模块。
A module can export a combination of its own declarations, selected imported classes, and imported modules.
Don't bother re-exporting pure service modules.
Pure service modules don't export declarable classes that another module could use.
For example, there's no point in re-exporting HttpModule because it doesn't export anything.
It's only purpose is to add http service providers to the application as a whole.
forRoot方法是什么?
What is the forRoot method?
静态方法forRoot是一个约定,它可以让开发人员更轻松的配置模块的提供商。
The forRoot static method is a convention that makes it easy for developers to configure the module's providers.
The RouterModule.forRoot method is a good example.
Apps pass a Routes object to RouterModule.forRoot in order to configure the app-wide Router service with routes.
RouterModule.forRoot returns a ModuleWithProviders.
You add that result to the imports list of the root AppModule.
Only call and import a .forRoot result in the root application module, AppModule.
Importing it in any other module, particularly in a lazy-loaded module,
is contrary to the intent and will likely produce a runtime error.
RouterModule也提供了静态方法forChild,用于配置惰性加载模块的路由。
RouterModule also offers a forChild static method for configuring the routes of lazy-loaded modules.
forRoot和forChild都是方法的约定名称,它们分别用于在根模块和特性模块中配置服务。
forRoot and forChild are conventional names for methods that
configure services in root and feature modules respectively.
Angular doesn't recognize these names but Angular developers do.
Follow this convention when you write similar modules with configurable service providers.
为什么服务提供商在特性模块中的任何地方都是可见的?
Why is a service provided in a feature module visible everywhere?
Providers listed in the @NgModule.providers of a bootstrapped module have application scope.
Adding a service provider to @NgModule.providers effectively publishes the service to the entire application.
This is by design.
Extensibility through module imports is a primary goal of the NgModule system.
Merging module providers into the application injector
makes it easy for a module library to enrich the entire application with new services.
By adding the HttpModule once, every application component can make http requests.
However, this might feel like an unwelcome surprise if you expect the module's services
to be visible only to the components declared by that feature module.
If the HeroModule provides the HeroService and the root AppModule imports HeroModule,
any class that knows the HeroServicetype can inject that service,
not just the classes declared in the HeroModule.
为什么在惰性加载模块中声明的服务提供商只对该模块自身可见?
Why is a service provided in a lazy-loaded module visible only to that module?
和启动时就加载的模块中的提供商不同,惰性加载模块中的提供商是局限于模块的。
Unlike providers of the modules loaded at launch,
providers of lazy-loaded modules are module-scoped.
When the Angular router lazy-loads a module, it creates a new execution context.
That context has its own injector,
which is a direct child of the application injector.
路由器把该惰性加载模块的提供商和它导入的模块的提供商添加到这个子注入器中。
The router adds the lazy module's providers and the providers of its imported modules to this child injector.
These providers are insulated from changes to application providers with the same lookup token.
When the router creates a component within the lazy-loaded context,
Angular prefers service instances created from these providers to the service instances of the application root injector.
When two imported modules, loaded at the same time, list a provider with the same token,
the second module's provider "wins". That's because both providers are added to the same injector.
当Angular尝试根据令牌注入服务时,它使用第二个提供商来创建并交付服务实例。
When Angular looks to inject a service for that token,
it creates and delivers the instance created by the second provider.
Every class that injects this service gets the instance created by the second provider.
Even classes declared within the first module get the instance created by the second provider.
If Module A provides a service for token 'X' and imports a module B
that also provides a service for token 'X', then Module A's service definition "wins".
When a module is loaded at application launch,
its @NgModule.providers have application-wide scope;
that is, they are available for injection throughout the application.
Imported providers are easily replaced by providers from another imported module.
Such replacement might be by design. It could be unintentional and have adverse consequences.
As a general rule, import modules with providers exactly once, preferably in the application's root module.
That's also usually the best place to configure, wrap, and override them.
Suppose a module requires a customized HttpBackend that adds a special header for all Http requests.
If another module elsewhere in the application also customizes HttpBackend
or merely imports the HttpModule, it could override this module's HttpBackend provider,
losing the special header. The server will reject http requests from this module.
要消除这个问题,就只能在应用的根模块AppModule中导入HttpModule。
To avoid this problem, import the HttpModule only in the AppModule, the application root module.
如果你必须防范这种“提供商腐化”现象,那就不要依赖于“启动时加载”模块的providers。
If you must guard against this kind of "provider corruption", don't rely on a launch-time module's providers.
Load the module lazily if you can.
Angular gives a lazy-loaded module its own child injector.
The module's providers are visible only within the component tree created with this injector.
如果你必须在应用程序启动时主动加载该模块,就改成在组件中提供该服务。
If you must load the module eagerly, when the application starts,
provide the service in a component instead.
继续看这个例子,假设某个模块的组件真的需要一个私有的、自定义的HttpBackend。
Continuing with the same example, suppose the components of a module truly require a private, custom HttpBackend.
Create a "top component" that acts as the root for all of the module's components.
Add the custom HttpBackend provider to the top component's providers list rather than the module's providers.
Recall that Angular creates a child injector for each component instance and populates the injector
with the component's own providers.
When a child of this component asks for the HttpBackend service,
Angular provides the local HttpBackend service,
not the version provided in the application root injector.
Child components make proper http requests no matter what other modules do to HttpBackend.
确保把模块中的组件都创建成这个顶级组件的子组件。
Be sure to create module components as children of this module's top component.
You can embed the child components in the top component's template.
Alternatively, make the top component a routing host by giving it a <router-outlet>.
Define child routes and let the router load module components into that outlet.
我应该把全应用级提供商添加到根模块AppModule中还是根组件AppComponent中?
Should I add application-wide providers to the root AppModule or the root AppComponent?
在根模块AppModule中注册全应用级提供商,而不是AppComponent中。
Register application-wide providers in the root AppModule, not in the AppComponent.
惰性加载模块及其组件可以注入AppModule中的服务,却不能注入AppComponent中的。
Lazy-loaded modules and their components can inject AppModule services;
they can't inject AppComponent services.
Register a service in AppComponent providers only if the service must be hidden
from components outside the AppComponent tree. This is a rare use case.
Angular registers all startup module providers with the application root injector.
The services created from root injector providers are available to the entire application.
They are application-scoped.
某些服务(比如Router)只有当注册进应用的根注入器时才能正常工作。
Certain services (such as the Router) only work when registered in the application root injector.
By contrast, Angular registers AppComponent providers with the AppComponent's own injector.
AppComponent services are available only to that component and its component tree.
They are component-scoped.
The AppComponent's injector is a child of the root injector, one down in the injector hierarchy.
For applications that don't use the router, that's almost the entire application.
But for routed applications, "almost" isn't good enough.
AppComponent services don't exist at the root level where routing operates.
Lazy-loaded modules can't reach them.
In the NgModule page sample applications, if you had registered UserService in the AppComponent,
the HeroComponent couldn't inject it.
The application would fail the moment a user navigated to "Heroes".
我应该把其它提供商注册到模块中还是组件中?
Should I add other providers to a module or a component?
Register a provider with a component when you must limit the scope of a service instance
to that component and its component tree.
Apply the same reasoning to registering a provider with a directive.
For example, a hero editing component that needs a private copy of a caching hero service should register
the HeroService with the HeroEditorComponent.
Then each new instance of the HeroEditorComponent gets its own cached service instance.
The changes that editor makes to heroes in its service don't touch the hero instances elsewhere in the application.
This question is addressed in the Why UserService isn't shared
section of the NgModules page,
which discusses the importance of keeping providers out of the SharedModule.
Both instances of the imported SharedModule would provide the UserService.
Angular registers one of them in the root app injector (see What if I import the same module twice?).
Then some component injects UserService, Angular finds it in the app root injector,
and delivers the app-wide singleton UserService. No problem.
When the router lazy loads the HeroModule, it creates a child injector and registers the UserService
provider with that child injector. The child injector is not the root injector.
When Angular creates a lazy HeroComponent, it must inject a UserService.
This time it finds a UserService provider in the lazy module's child injector
and creates a new instance of the UserService.
This is an entirely different UserService instance
than the app-wide singleton version that Angular injected in one of the eagerly loaded components.
To demonstrate, run the live example / downloadable example.
Modify the SharedModule so that it provides the UserService rather than the CoreModule.
Then toggle between the "Contact" and "Heroes" links a few times.
The username goes bonkers as the Angular creates a new UserService instance each time.
Angular adds @NgModule.providers to the application root injector, unless the module is lazy loaded.
For a lazy-loaded module, Angular creates a child injector and adds the module's providers to the child injector.
This means that a module behaves differently depending on whether it's loaded during application start
or lazy loaded later. Neglecting that difference can lead to adverse consequences.
The answer is grounded in a fundamental characteristic of the Angular dependency-injection system.
An injector can add providers until it's first used.
Once an injector starts creating and delivering services, its provider list is frozen; no new providers are allowed.
When an applications starts, Angular first configures the root injector with the providers of all eagerly loaded modules
before creating its first component and injecting any of the provided services.
Once the application begins, the app root injector is closed to new providers.
Time passes and application logic triggers lazy loading of a module.
Angular must add the lazy-loaded module's providers to an injector somewhere.
It can't added them to the app root injector because that injector is closed to new providers.
So Angular creates a new child injector for the lazy-loaded module context.
我要如何知道一个模块或服务是否已经加载过了?
How can I tell if a module or service was previously loaded?
Some modules and their services should be loaded only once by the root AppModule.
Importing the module a second time by lazy loading a module could produce errant behavior
that may be difficult to detect and diagnose.
To prevent this issue, write a constructor that attempts to inject the module or service
from the root app injector. If the injection succeeds, the class has been loaded a second time.
You can throw an error or take other remedial action.
Certain NgModules (such as BrowserModule) implement such a guard,
such as this CoreModule constructor from the NgModules page.
src/app/core/core.module.ts (Constructor)
constructor (@Optional()@SkipSelf() parentModule:CoreModule){if(parentModule){thrownewError('CoreModule is already loaded. Import it in the AppModule only');}}
什么是入口组件?
What is an entry component?
Angular根据其类型不可避免地加载的组件是入口组件,
An entry component is any component that Angular loads imperatively by type.
而通过组件选择器声明式加载的组件则不是入口组件。
A component loaded declaratively via its selector is not an entry component.
Most application components are loaded declaratively.
Angular uses the component's selector to locate the element in the template.
It then creates the HTML representation of the component and inserts it into the DOM at the selected element.
These aren't entry components.
也有少量组件只会被动态加载,并且永远不会被组件的模板所引用。
A few components are only loaded dynamically and are never referenced in a component template.
The bootstrapped root AppComponent is an entry component.
True, its selector matches an element tag in index.html.
But index.html isn't a component template and the AppComponent
selector doesn't match an element in any component template.
Angular loads AppComponent dynamically because it's either listed by type in @NgModule.bootstrap
or boostrapped imperatively with the module's ngDoBootstrap method.
Components in route definitions are also entry components.
A route definition refers to a component by its type.
The router ignores a routed component's selector (if it even has one) and
loads the component dynamically into a RouterOutlet.
The compiler can't discover these entry components by looking for them in other component templates.
You must tell it about them by adding them to the entryComponents list.
Angular会自动把下列类型的组件添加到模块的entryComponents中:
Angular automatically adds the following types of components to the module's entryComponents:
那些出现在@NgModule.bootstrap列表中的组件。
The component in the @NgModule.bootstrap list.
那些被路由定义引用的组件。
Components referenced in router configuration.
我们并不需要显式的引用这些组件 —— 虽然引用了也没坏处。
You don't have to mention these components explicitly, although doing so is harmless.
What's the difference between a bootstrap component and an entry component?
A bootstrapped component is an entry component
that Angular loads into the DOM during the bootstrap (application launch) process.
Other entry components are loaded dynamically by other means, such as with the router.
The @NgModule.bootstrap property tells the compiler that this is an entry component and
it should generate code to bootstrap the application with this component.
Angular adds certain components to entry components automatically.
Components listed in @NgModule.bootstrap are added automatically.
Components referenced in router configuration are added automatically.
These two mechanisms account for almost all entry components.
Although it's harmless to add components to this list,
it's best to add only the components that are truly entry components.
Don't include components that are referenced
in the templates of other components.
Entry components are also declared.
Why doesn't the Angular compiler generate code for every component in @NgModule.declarations?
Then you wouldn't need entry components.
The reason is tree shaking. For production apps you want to load the smallest, fastest code possible.
The code should contain only the classes that you actually need.
It should exclude a component that's never used, whether or not that component is declared.
In fact, many libraries declare and export components you'll never use.
If you don't reference them, the tree shaker drops these components from the final code package.
The compiler starts with the entry components,
then it generates code for the declared components it finds in an entry component's template,
then for the declared components it discovers in the templates of previously compiled components,
and so on. At the end of the process, the compiler has generated code for every entry component
and every component reachable from an entry component.
如果该组件不是入口组件或者没有在任何模板中发现过,编译器就会忽略它。
If a component isn't an entry component or wasn't found in a template,
the compiler omits it.
What kinds of modules should I have and how should I use them?
有哪些类型的模块?我应该如何使用它们?
每个应用都不一样。根据不同程度的经验,开发者会做出不同的选择。一些建议和向导具有更加广泛的吸引力。
Every app is different. Developers have various levels of experience and comfort with the available choices.
Some suggestions and guidelines appear to have wide appeal.
下面这些初步的指南仅来自在少量应用中使用Angular模块时的早期体验。
仅供参考。
The following is preliminary guidance based on early experience using NgModules in a few applications.
Read with appropriate caution and reflection.
Create a SharedModule with the components, directives, and pipes that you use
everywhere in your app. This module should consist entirely of declarations,
most of them exported.
The SharedModule should not have providers for reasons explained previously.
Nor should any of its imported or re-exported modules have providers.
If you deviate from this guideline, know what you're doing and why.
This page sample departs from that advice by declaring and exporting two components that are
only used within the root AppComponent declared by AppModule.
Someone following this guideline strictly would have declared these components in the AppModule instead.
特性模块
Feature Modules
围绕特定的业务领域、工作流和工具集来为应用创建特性模块。
Create feature modules around specific application business domains, user workflows, and utility collections.
特性模块一般可分成下面这几种:
Feature modules tend to fall into one of the following groups:
Real-world modules are often hybrids that purposefully deviate from the following guidelines.
These guidelines are not laws;
follow them unless you have a good reason to do otherwise.
特性模块
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.
领域特性模块几乎总是由declarations构成。只有顶级组件会被导出。
Domain feature modules consist mostly of declarations.
Only the top component is exported.
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.
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.
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 rootAppModule,
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.
In modern JavaScript, every file is a module
(see the Modules page of the Exploring ES6 website).
Within each file you write an export statement to make parts of the module public:
exportclassAppComponent{...}
然后,我们可以在其它模块中import那部分:
Then you import a part in another module:
import{AppComponent}from'./app.component';
这种模块化方式是JavaScript语言中的特性。
This kind of modularity is a feature of the JavaScript language.
而Angular模块是Angular本身的特性。
An NgModule is a feature of Angular itself.
Angular的NgModule也有自己的imports和exports来达到类似的目的。
Angular's NgModule also has imports and exports and they serve a similar purpose.
You import other NgModules so you can use their exported classes in component templates.
You export this NgModule's classes so they can be imported and used by components of other modules.
Angular的模块类与JavaScript的模块类有三个主要的不同点:
The NgModule classes differ from JavaScript module class in the following key ways:
Instead of defining all member classes in one giant file (as in a JavaScript module),
you list the module's classes in the @NgModule.declarations list.
The NgModule is also special in another way.
Unlike JavaScript modules, an NgModule can extend the entire application with services
by adding providers to the @NgModule.providers list.
这些提供的服务不仅仅从属于当前模块,其作用范围也不局限于模块中声明的类。它们在哪里都能用。
The provided services don't belong to the module nor are they scoped to the declared classes.
They are available everywhere.
这里是一个带有imports、exports和declarations的Angular模块类。
Here's an NgModule class with imports, exports, and declarations.
The Angular compiler finds a component or directive in a template when it can match the selector of that
component or directive to some HTML in that template.
编译器通过分析模板HTML中的管道语法中是否出现了特定的管道名来查找对应的管道。
The compiler finds a pipe if the pipe's name appears within the pipe syntax of the template HTML.
The Angular compiler converts the application code you write into highly performant JavaScript code.
The @NgModule metadata play an important role in guiding the compilation process.
The code you write isn't immediately executable.
Consider components.
Components have templates that contain custom elements, attribute directives, Angular binding declarations,
and some peculiar syntax that clearly isn't native HTML.
Angular编译器读取模板的HTML,把它和相应的组件类代码组合在一起,并产出组件工厂。
The Angular compiler reads the template markup,
combines it with the corresponding component class code, and emits component factories.
A component factory creates a pure, 100% JavaScript representation
of the component that incorporates everything described in its @Component metadata:
the HTML, the binding instructions, the attached styles.
由于指令和管道都出现在组件模板中,Angular编译器*也同样会把它们组合到编译成的组件代码中。
Because directives and pipes appear in component templates,
the Angular compiler incorporates them into compiled component code too.
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.
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 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 referencethis module's HeroComponent
if it imports this module and this module exports HeroComponent.
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.
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也可以引导多个引导组件,它们每一个都在宿主页面中有自己的位置。
Angular can launch with multiple bootstrap components,
each with its own location in the host web page.
引导组件会自动成为entryComponent。
A bootstrap component is automatically an entryComponent.
Most developers never set this property.
The 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 <router-outlet>.
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.
使用路由器之外的手段动态加载到DOM中的组件。
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.