TLDR:
-
CoreModule 应该只有 services 并且在 AppModule 中只导入一次。
-
SharedModule 应该包含除 services 之外的任何内容,并导入到所有需要共享内容的模块中(也可以是 AppModule)。
但是:
现实世界的模块通常是故意偏离[上述]准则的混合体。这些准则不是法律;除非您有充分的理由不这样做,否则请遵循它们。
所以,在浏览了整个NgModules' docs(加上一些其他的东西来理解上下文)之后,我很容易找到你的第二个和第三个问题的答案
there。他们是:
共享模块
- 使用
components、directives 和pipes 创建一个SharedModule,您可以在应用程序的任何地方使用它。此模块应完全由 declarations 组成,其中大部分已导出。
-
SharedModule 可以重新导出其他小部件模块,例如 CommonModule、FormsModule,以及带有您最广泛使用的 UI 控件的模块。
-
SharedModule 不应该有providers,原因如前所述。它的任何导入或重新导出的模块也不应该有提供者。如果您偏离本指南,请了解您在做什么以及为什么。
- 在您的功能模块中导入
SharedModule,包括在应用启动时加载的和稍后延迟加载的。
核心模块
- 为您在应用程序启动时加载的单例服务创建一个带有
providers 的CoreModule。
- 仅在根
AppModule 中导入CoreModule。切勿在任何其他模块中导入 CoreModule。
- 考虑将
CoreModule 设为没有declarations 的纯服务模块。
虽然这些比上面的TLDR 版本更详细,您现在可以继续编写代码,但它提到了一些您必须阅读文档才能理解的内容(即“小部件模块”、“之前解释的原因” ,“纯服务模块”),而且它也没有回答您的第一个问题。
那么让我们试着去做吧!
为什么我需要两个模块?
您不需要两个模块。这是文档中的内容:
在一个包含几个组件的简单应用程序中,您只需要根模块。
话虽如此,重要的是先提出一个不同的问题:
为什么人们将他们的项目组织成多个模块?
对此的基本解释紧随文档中的上述声明之后:
随着应用程序的增长,您将根模块重构为代表相关功能集合的功能模块。然后将这些模块导入根模块。
但你问“为什么?”这需要的不仅仅是基本的解释。因此,让我们开始解释如果您的应用开始增长并且您没有将功能分离到功能模块中可能会发生的一些问题:
- 根模块开始变得混乱,代码难以阅读和使用,因为它必须导入所有依赖项(例如第 3 方模块),提供所有服务并声明所有组件、指令和管道。应用需要的越多,这个模块就会越大。
- 不同的功能之间没有明确的界限,这使得不仅要了解应用程序的结构,还要在团队中承担不同的职责变得更加困难。
- 您可以开始解决应用程序不同部分之间的冲突。例如,如果您的应用程序的两个不同部分有执行相同操作的指令或组件,则您要么必须开始使用更长的名称来区分它们,要么在导入时重命名它们。
虽然你可能认为上面的例子并不完全是问题(也许你一个人工作,可以忍受自己的烂摊子或者你所有的队友也都烂摊子),但请记住,其他人肯定不会同意你的观点,并且这就是为什么您“一直在观看几个项目......使用这种方法”。
考虑到您同意这一点并希望将您不断发展的应用组织成功能模块,请注意文档中的以下声明:
根模块和功能模块共享相同的执行上下文。它们共享相同的依赖注入器,这意味着一个模块中的服务可供所有人使用。
这些模块具有以下显着的技术差异:
- 您启动根模块以启动应用程序;您导入一个功能模块来扩展应用程序。
- 功能模块可以向其他模块公开或隐藏其实现。
永远不会忘记的信息: “一个模块中的服务可用于所有 [模块]”,而其他东西,如组件、指令和管道必须注入每个模块中想要使用它们。
有了这些信息,我们现在可以通过回答以下问题更接近您想了解的内容:
所有功能模块都一样吗?
不! 至少建议它们不应该相等,因为建议你不应该只有根模块,但你可以做任何你想做的事情。但你不应该。
文档有一个表格,显示了建议的功能模块组之间的差异。让我们看一下它的摘录:
FEATURE SHOULD HAVE SHOULD HAVE SHOULD HAVE
MODULE DECLARATIONS PROVIDERS EXPORTS
Domain Yes Rare Top component
Routed Yes Rare No
Routing No Yes (Guards) RouterModule
Service No Yes No
Widget Yes Rare Yes
注意!他们很清楚这是一个......
...基于早期使用经验的初步指导
一些应用程序中的 NgModules。
因此,同样,您不必拘泥于这些准则,可能会发生偏差,但您应该知道自己在做什么以及为什么。
现在我们来分析一下这张表:
-
Service 和 Widget 组是唯一在每列中具有完全不同值的组。
-
Domain 和Routed 组与Widget 组基本相同,只是导出有限或没有导出。
-
Routing 组基本上是一个Service 组,有一个导出例外并且仅限于特定的提供者。
所以,让我们考虑Domain、Routed 和Routing 组只是Service 或Widget 的变体,并关注最后两个。
服务应该引起您的注意。请记住,您永远不应该忘记“一个模块中的服务对所有 [模块] 都可用”?好吧,如果他们调用功能模块组Services,那是因为它必须与其他模块隔离,因此只能导入一次。例如,您可以拥有一个由 SignUpService、SignInService、SocialAuthService 和 UserProfileService 等服务组成的 UserModule。无论您在哪里导入 UserModule,它的所有服务都将在应用程序范围内可用。根据上表,它不应该有声明或导出,只有提供者。
Widgets 听起来更通用,但它应该告诉你一些事情。请记住,您也永远不要忘记“必须在每个想要使用它们的模块中注入其他东西,例如组件、指令和管道。”?所以这是您将用于这些的模块类型。例如,您可以使用 UIModule 和 ButtonComponent、NavComponent、SlideshowComponent、HighlightLinkDirective、CtaPipe。每次您需要使用其导出的一个或所有元素时,您只需导入 UIModule。
因此,基本上,由于 Angular 处理服务的方式,当您开始将功能拆分为功能模块时,您必须将服务隔离到它们自己的模块中,而其他东西可以在它们之间随意组织.
CoreModule 和 SharedModule 如何适应这个?
为简单起见,CoreModule 是 Service 模块,SharedModule 是 Widget 模块。这就是为什么您应该只在AppModule 中导入第一个,而在所有需要它的模块中导入后者。在我上面的示例中,UserModule 将由 CoreModule 导入,UIModule 将由 SharedModule 导入。
但是,如前所述,这些是指导方针,可能会发生偏差,即使在他们自己的示例中,他们在 CoreModule 中声明了组件,但需要注意:
此页面示例通过声明和导出 [在CoreModule] 中的两个组件来偏离该建议,这些组件仅在 AppModule 声明的根 AppComponent 中使用。严格遵循此准则的人会改为在 AppModule 中声明这些组件。
就我个人而言,我认为最大的困惑在于命名选择。通常,人们会认为作为应用程序核心一部分的所有内容(即用户资料、导航栏、加载栏、烤面包机等)都将进入CoreModule,而跨多个功能共享的所有内容都将进入SharedModule。
这实际上不是真的,而且有点误导,因为所有服务都是“本质上”在所有模块之间共享的,SharedModule 中不应包含任何服务,NavbarComponent 是您的核心的一部分应用程序和任何组件都不应包含在 CoreModule 中。
在任何情况下,我们都建议您遵循指南,直到您找到不这样做的理由。
以下是上表的其余部分,以帮助更好地理解指南:
FEATURE CAN BE SOME
MODULE IMPORTED BY EXAMPLES
Domain Feature, AppModule ContactModule (before routing)
Routed Nobody ContactModule, DashboardModule,
Routing Feature (for routing) AppRoutingModule, ContactRoutingModule
Service AppModule HttpModule, CoreModule
Widget Feature CommonModule, SharedModule
干杯!