【问题标题】:Angular2: CoreModule vs SharedModuleAngular2:CoreModule 与 SharedModule
【发布时间】:2017-03-09 12:53:17
【问题描述】:

有人能解释一下SharedModuleCoreModule 代表什么吗?

我一直在观察有几个项目正在使用这种方法来构建它的 Angular 项目。

  1. 为什么需要两个模块?
  2. 我应该什么时候导入每一个?
  3. importsexportsdeclarations应该各有哪一个?

【问题讨论】:

  • 我知道您问这个问题已经 7 个月了,但是由于其他答案不完整和/或具有误导性,并且您不接受其中任何一个,因此我已尝试详细回答.如果您认为它被正确回答以帮助可能有同样疑问的其他人,请接受它。干杯!
  • 我写了一篇文章把这两个概念说清楚,你可以在这里找到:medium.com/@benmohamehdi/…

标签: angular


【解决方案1】:

TLDR:

  1. CoreModule 应该只有 services 并且在 AppModule 中只导入一次。
  2. SharedModule 应该包含除 services 之外的任何内容,并导入到所有需要共享内容的模块中(也可以是 AppModule)。

但是:

现实世界的模块通常是故意偏离[上述]准则的混合体。这些准则不是法律;除非您有充分的理由不这样做,否则请遵循它们。


RTFM:

所以,在浏览了整个NgModules' docs(加上一些其他的东西来理解上下文)之后,我很容易找到你的第二个和第三个问题的答案 there。他们是:

共享模块

  • 使用componentsdirectivespipes 创建一个SharedModule,您可以在应用程序的任何地方使用它。此模块应完全由 declarations 组成,其中大部分已导出。
  • SharedModule 可以重新导出其他小部件模块,例如 CommonModuleFormsModule,以及带有您最广泛使用的 UI 控件的模块。
  • SharedModule 不应该有providers,原因如前所述。它的任何导入或重新导出的模块也不应该有提供者。如果您偏离本指南,请了解您在做什么以及为什么。
  • 在您的功能模块中导入SharedModule,包括在应用启动时加载的和稍后延迟加载的。

核心模块

  • 为您在应用程序启动时加载的单例服务创建一个带有providersCoreModule
  • 仅在根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。

因此,同样,您不必拘泥于这些准则,可能会发生偏差,但您应该知道自己在做什么以及为什么。

现在我们来分析一下这张表:

  • ServiceWidget 组是唯一在每列中具有完全不同值的组。
  • DomainRouted 组与Widget 组基本相同,只是导出有限或没有导出。
  • Routing 组基本上是一个Service 组,有一个导出例外并且仅限于特定的提供者。

所以,让我们考虑DomainRoutedRouting 组只是ServiceWidget 的变体,并关注最后两个。

服务应该引起您的注意。请记住,您永远不应该忘记“一个模块中的服务对所有 [模块] 都可用”?好吧,如果他们调用功能模块组Services,那是因为它必须与其他模块隔离,因此只能导入一次。例如,您可以拥有一个由 SignUpServiceSignInServiceSocialAuthServiceUserProfileService 等服务组成的 UserModule。无论您在哪里导入 UserModule,它的所有服务都将在应用程序范围内可用。根据上表,它不应该有声明或导出,只有提供者。

Widgets 听起来更通用,但它应该告诉你一些事情。请记住,您也永远不要忘记“必须在每个想要使用它们的模块中注入其他东西,例如组件、指令和管道。”?所以这是您将用于这些的模块类型。例如,您可以使用 UIModuleButtonComponentNavComponentSlideshowComponentHighlightLinkDirectiveCtaPipe。每次您需要使用其导出的一个或所有元素时,您只需导入 UIModule

因此,基本上,由于 Angular 处理服务的方式,当您开始将功能拆分为功能模块时,您必须将服务隔离到它们自己的模块中,而其他东西可以在它们之间随意组织.

CoreModuleSharedModule 如何适应这个?

为简单起见,CoreModuleService 模块,SharedModuleWidget 模块。这就是为什么您应该只在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

干杯!

【讨论】:

  • 很酷,你花时间写了这一切。你能评论以下内容吗?他们在angular.io/guide/styleguide#core-feature-module 中写道:Do gather application-wide, single use components in the CoreModule. Import it once (in the AppModule) when the app starts and never import it anywhere else. (e.g. NavComponent and SpinnerComponent).。您是否看到将 NavBarComponent 等组件放入 CoreModule 的缺点?我赞成你的回答;但是,请对 CoreModule 中的导航栏发表评论,请:)。
  • 我打赌(并希望)否决这个答案的人不是故意这样做的
  • @KarolDepka 不幸的是,文档和指南是由不同的人编写的。但正如他们两个都提到的,它们只是建议,每个项目和开发人员可能会觉得稍微偏离它们会更舒服。我个人会将 NavBarComponent 直接放入 AppModule。
  • @EresDev 我不确定您所说的“页面”是什么意思,但是如果每个页面都有自己的模块并且其中只有一些会使用该组件,那么您显然在那里有一个共享组件。但是,如果您有一个 PagesModule,其中声明了所有页面组件,并且此“主菜单”没有被任何其他模块使用,您可以简单地将其导入 PagesModule。
  • 所有对 CoreModule 的引用都已从 Angular 文档中删除;这不再是推荐的做法。使用 providedIn: 'root' 的单例服务部分似乎是替代 angular.io/guide/singleton-services
【解决方案2】:

我自己确实使用这种方法,这就是为什么/如何:
(这是一种方法,也许其他人会有 != 很好的想法)

我喜欢让app.module 尽可能干净。如果您想使用通用或使用 AOT 构建您的项目(当不使用 angular-cli 时),您可能需要有一个重复的 app.module 并在所有这些文件中进行少量更改。

因此,如果您将许多模块导入您的 app.module,您必须在不同的文件中更新该列表。

core.module 来了:
将您只想导入一次的每个模块放在这里。主要是具有forRoot 方法的模块(那些导出其提供者并且应该只导入一次的模块)。

在这里也导入您的供应商。 (例如,如果您使用 ngrx,请在此处声明您的商店)。

那么,shared.module
将您必须在您的应用程序中重用的每个模块(CommonModule、HttpModule、RouterModule、MaterialModule、FlexLayoutModule 等)。

最后,app.module
导入 app.module 您的 core.module 仅在此处。 CoreModule 应该只加载一次。在你所有的 submobules 中,你可以加载 SharedModule

使用该配置,如果您需要为通用或其他人创建另一个 app.module,则不必在不同的文件中复制和维护整个模块列表。只需导入 core.module 即可。

【讨论】:

  • 这不是 StyleGuide for Angular 所说的。除非我理解错了
  • 那你明白了什么?
  • “请导入 CoreModule 中资产所需的所有模块(例如 CommonModule 和 FormsModule)。”。 StyleGuide 还说将 CommonModule 导入 SharedModule。那有什么区别呢?
  • 我已经为具有这种设置的ngrx做了一个小启动器,看看github.com/maxime1992/angular-ngrx-starter/tree/master/src/app
  • 但是对于我想在我的应用程序中使用的模块,我真的只想在我的困惑所在的地方导入它们。亲!
【解决方案3】:

根据 Angular 的风格指南和我的观察:

CoreModule(core.module.ts) 核心功能模块

所有应该是单例的服务都应该在这里提供。例如HelperServiceLoggerService

应在CoreModule 中声明应用程序范围的组件,例如headerfooter

CoreModule 提供一个或多个单例服务。 Angular 向应用程序根注入器注册提供程序,使每个服务的单例实例可供任何需要它们的组件使用,无论该组件是急切加载还是延迟加载。

只有根 AppModule 应该导入 CoreModule。

SharedModule(shared.module.ts) 共享功能模块

在共享模块中声明组件、指令和管道,当这些项目将被其他功能模块中声明的组件重用和引用时

建议避免在共享模块中使用services。服务通常是为整个应用程序或特定功能模块提供一次的单例。

所有功能模块所需的模块都应导入 SharedModule 中,例如 CommonModuleFormsModule

可共享组件/管道/指令的声明应在 SharedModule 中。如果这些组件/管道/指令需要被其他功能模块使用,则必须导出。

如果使用 Material,最好是导入和重新导出 Angular Material 组件。

参考资料: CoreModule, SharedModule

【讨论】:

    【解决方案4】:

    我认为这个问题太笼统了,对于笼统的问题,你会有笼统的答案......例如,共享模块旨在保留几个组件/模块使用的内容:

    import { NgModule }            from '@angular/core';
    import { CommonModule }        from '@angular/common'; 
    import { FormsModule, ReactiveFormsModule } from '@angular/forms';
    
    //import { AwesomePipe }         from './awesome.pipe';
    //import { HighlightDirective }  from './highlight.directive';
    
    @NgModule({
      exports:      [ /*AwesomePipe, HighlightDirective,*/
                      CommonModule, FormsModule, ReactiveFormsModule ]
    })
    export class SharedModule { }
    

    CoreModule 更像是您认为的页面核心(Nav、Spinner、Alert...)。这很有启发性,我认为取决于你的感觉。例如:

    import { NgModule, Optional, SkipSelf } from '@angular/core';
    
    import { NavComponent } from './nav/nav.component';
    import { SpinnerComponent } from './spinner/spinner.component';
    import { SpinnerService } from './spinner/spinner.service';
    import { AlertComponent }     from './alert/alert.component';
    import { AlertService }       from './alert/alert.service';
    
    import { SharedModule }       from '../shared/shared.module';
    
    import { CoreRoutingModule } from './core-routing.module';
    
    
    @NgModule({
      imports: [ 
        SharedModule, 
        CoreRoutingModule,
      ],
      exports: [//Other modules use these components, so we export them
        AlertComponent, 
        NavComponent, 
        SpinnerComponent,
    
        ],
      declarations: [ //we use them in CoreModule, so we declare them
        AlertComponent, 
        NavComponent, 
        SpinnerComponent,
    
        ],
      providers: [
        SpinnerService, 
        AlertService,
    
      ]
    })
    export class CoreModule {
        constructor (@Optional() @SkipSelf() parentModule: CoreModule) {
          if (parentModule) {
            throw new Error(
              'CoreModule est déjà chargé. Importer le uniquement dans AppModule');
          }
        }
    }
    

    【讨论】:

    • 这并不完全正确。检查我的答案,我在其中解释了原因。
    • 你不应该在 CoreModule 中导入 SharedModule
    • @andreasonny83 为什么?
    • @KarolDepka 是在应用程序的根模块(AngularCLI 中的 AppModule)中导入 CoreModule 的最佳实践。所有要安装在功能模块中的可重用模块都应该位于 SharedModule 中。这样,您的根应用程序将不需要加载所有共享模块来引导您的应用程序。在 CoreModule 中导入共享模块会抵消拥有 SharedModule 的好处,因为它们已经安装在您的核心应用程序模块中。
    • 如果CoreModule中没有导入RouterModule,如何让NavComponent routerLink工作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-24
    • 1970-01-01
    • 2016-09-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多