Angular2: CoreModule vs SharedModule

Может ли кто-нибудь объяснить, что SharedModule и CoreModule?

Я наблюдал за несколькими проектами, используя этот подход, чтобы строить свои угловые проекты.

  1. Зачем мне нужны два модуля?
  2. Когда следует импортировать каждый из них?
  3. Какие imports, exports, declarations должны иметь каждый из них?

Ответ 1

TL;DR:

  1. CoreModule должен иметь только services и импортироваться только один раз в AppModule.
  2. SharedModule должен иметь ничего, кроме services и импортироваться во все модули, которым нужны общие материалы (которые также могут быть AppModule).

Но:

Модули реального мира часто являются гибридами, которые целенаправленно отклоняются от руководящих принципов [выше]. Эти руководящие принципы не являются законами; следуйте им, если у вас нет веских оснований для этого.


RTFM:

Итак, пройдя все документы NgModules (плюс некоторые другие вещи, чтобы понять контекст), я легко нашел ответ на ваши 2-й и 3-й вопросы там. Вот они:

SharedModule

  • Создание SharedModule с components, directives и pipes, которые используются во всем мире в вашем приложении. Этот модуль должен состоять полностью из declarations, большинство из которых экспортируются.
  • SharedModule может реэкспортировать другие модули виджетов, такие как CommonModule, FormsModule и модули с помощью элементов управления пользовательского интерфейса, которые вы используете наиболее широко.
  • SharedModule не должен иметь providers по причинам, описанным ранее. Также ни один из импортированных или реэкспортируемых модулей не имеет поставщиков. Если вы отклоняетесь от этого руководства, знайте, что вы делаете и почему.
  • Импортируйте SharedModule в свои функциональные модули, как загруженные при запуске приложения, так и те, которые вы лените позже.

CoreModule

  • Создайте CoreModule с providers для служб singleton, которые вы загружаете, когда приложение запускается.
  • Импортируйте CoreModule в корневой AppModule. Никогда не импортируйте CoreModule в любой другой модуль.
  • Подумайте о том, чтобы сделать CoreModule чистым сервисным модулем без declarations.

Хотя они более подробные, чем версия TL;DR выше, и теперь вы можете продолжать и продолжать кодирование, в ней упоминаются некоторые вещи, которые вы должны прочитать, чтобы понять документы (например, "модуль виджета", "причины, объясненные ранее", "чистые служебные модули "), и он также не отвечает на ваш первый вопрос.

Так что попробуй это сделать!


Зачем мне нужны два модуля?

Вам не нужны два модуля. Это то, что находится в документах:

Корневой модуль - это все, что вам нужно в простом приложении с несколькими компонентами.

С учетом сказанного важно сначала задать другой вопрос:

Почему люди организуют свои проекты на нескольких модулях?

Основное объяснение этого происходит сразу после вышеупомянутого утверждения в документах:

По мере того, как приложение растет, вы реорганизуете корневой модуль в функциональные модули, которые представляют коллекции связанных функций. Затем вы импортируете эти модули в корневой модуль.

Но вы спросили: "Почему?" и это требует более чем базового объяснения. Поэтому давайте начнем объяснять, какие проблемы могут возникнуть, если ваше приложение начнет расти, и вы не разделяете функциональные возможности на функциональные модули:

  • Корневой модуль начинает загромождать код, который трудно читать и работать, поскольку он должен импортировать все зависимости (например, сторонние модули), предоставлять все службы и объявлять все компоненты, директивы и каналы. Чем больше понадобится приложение, тем больше будет этот модуль.
  • У разных функций нет четкой границы между ними, что усложняет задачу, а не просто понимать структуру приложения, но также имеет разные обязанности в команде.
  • Вы можете начать решать конфликты между различными частями вашего приложения. Например, если у вас есть директивы или компоненты, которые делают то же самое в двух разных частях вашего приложения, вам придется либо начать использовать более длинные имена, чтобы их отличить, либо переименовать их при импорте.

Хотя вы можете подумать, что приведенные выше примеры не являются точно проблемами (возможно, вы работаете в одиночку и можете жить со своим собственным беспорядком или все ваши товарищи по команде тоже беспорядочны), имейте в виду, что другие люди, безусловно, не согласятся с вами, и почему вы "наблюдали за несколькими проектами [там]... используя этот подход".

Учитывая, что вы согласны с этим и хотите организовать растущее приложение в функциональных модулях, обратите внимание на следующие заявления из документов:

Корневой модуль и модуль функций имеют один и тот же контекст выполнения. Они имеют один и тот же инжектор зависимости, что означает, что услуги в одном модуле доступны для всех.

Модули имеют следующие существенные технические отличия:

  • Вы загружаете корневой модуль для запуска приложения; вы импортируете модуль функций для расширения приложения.
  • Функциональный модуль может выставлять или скрывать свою реализацию из других модулей.

Информация, которую нельзя забывать: "услуги в одном модуле доступны для всех [модулей]", в то время как в каждом модуле, который хочет их использовать, нужно вводить другие вещи, такие как "Компоненты", "Директивы" и "Трубы".

С этой информацией мы можем теперь приблизиться к тому, что вы хотите знать, отвечая на следующий вопрос:

Все ли функциональные модули равны?

НЕТ! По крайней мере, предполагается, что они не должны быть равными, так как предлагается, чтобы у вас не было только корневого модуля, но вы можете делать все, что хотите. Но вы не должны.

В документах есть таблица, показывающая различия между предложенными группами модулей функций. Позвольте взглянуть на выдержку из нее:

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, что, поскольку он должен быть изолирован от других модулей, так что можно импортировать только один раз. Например, вы можете иметь UserModule который состоит из таких сервисов, как SignUpService, SignInService, SocialAuthService и UserProfileService. Где бы вы ни импортировали этот UserModule, все его службы будут доступны для приложений. И согласно приведенной выше таблице, он не должен иметь деклараций и экспорта, а только поставщиков.

Виджеты звучат более обобщенно, но он должен вам что-то сказать. Помните, что вы также никогда не должны забывать, что "в каждом модуле, который хочет их использовать, нужно вводить другие вещи, такие как" Компоненты "," Директивы "и" Трубы "."? Так что это тип модуля, который вы будете использовать для них. Например, вы можете иметь UIModule с ButtonComponent, NavComponent, SlideshowComponent, HighlightLinkDirective, CtaPipe. И каждый раз, когда вам нужно использовать один или все экспортированные элементы, вы импортируете только UIModule.

Итак, в основном, из-за того, как Angular имеет дело с Сервисами, когда вы начинаете разделять функциональные возможности на функциональные модули, вам нужно изолировать службы в своих собственных модулях, а другие могут быть организованы между ними по вашему желанию.

Как CoreModule и SharedModule вписываются в это?

Чтобы упростить это, CoreModule является Service модулем, а SharedModule - модулем Widget. И поэтому вы должны импортировать первый только один раз в AppModule а последний - во все модули, которые в нем нуждаются. Из приведенных выше примеров UserModule будет импортироваться с помощью CoreModule и UIModule с помощью SharedModule.

Но, как указывалось ранее, это рекомендации и отклонения могут произойти, даже в своих собственных примерах они объявляют компоненты в CoreModule, но с наблюдением:

Этот образец страницы отходит от этого совета, объявляя и экспортируя [в CoreModule ] два компонента, которые используются только в корневом AppComponent, объявленном AppModule. Кто-то, следующий за этим руководством, строго заявил бы об этих компонентах в AppModule.


Лично я считаю, что самая большая путаница касается выбора наименований. В общем, люди будут думать, что все, что является частью вашего ядра приложения (например, пользовательский материал, NavBar, панель загрузки, тостеры и т.д.), SharedModule в 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

Ура!

Ответ 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 должен загружаться только один раз. Во всех ваших подмодулях вы можете загрузить SharedModule.

С этой конфигурацией, если вам нужно создать еще один app.module для универсального или других, вам не нужно копировать и поддерживать весь список модулей в разных файлах. Просто импортируйте core.module и вам хорошо идти.

Ответ 3

Согласно руководству по стилю Angular и моим наблюдениям:

CoreModule (core.module.ts) Основной функциональный модуль

Все услуги, которые должны быть одноточечными, должны предоставляться здесь. Например, HelperService, LoggerService.

Компонент Application wide должен быть объявлен в CoreModule как header, footer.

CoreModule предоставляет один или несколько однопользовательских сервисов. Угловые регистры провайдеров с корневым инжектором приложения, делая экземпляр singleton каждой службы доступным для любого компонента, который им нужен, независимо от того, загружен ли этот компонент или лениво загружен.

Только корневой AppModule должен импортировать CoreModule.

SharedModule (shared.module.ts) Общий функциональный модуль

объявлять компоненты, директивы и трубы в совместно используемом модуле, когда эти элементы будут повторно использоваться и ссылаться на компоненты, объявленные в других функциональных модулях

Предлагается избегать использования services в общих модулях. Услуги, как правило, являются одноточечными, которые предоставляются один раз для всего приложения или в определенном функциональном модуле.

Модули, требуемые всеми функциональными модулями, должны быть импортированы в SharedModule, например CommonModule & FormsModule.

Объявление разделяемого компонента/трубы/директивы должно быть в SharedModule. Если эти компоненты /pipe/directive должны использоваться другим функциональным модулем, они должны экспортироваться.

При использовании материала лучше всего импортировать и реэкспортировать компоненты углового материала.

Ссылки: 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');
      }
    }
}