Posted at

NgModule FAQs

More than 1 year has passed since last update.

https://angular.io/guide/ngmodule-faq

ほぼGoogle翻訳です。いくつかスキップしているものもあります。


NgModule FAQs

ここでは多くの開発者が聞くNgModuleの設計と実装について答える。


What classes should I not add to declarations ?

declarations に書くのはコンポーネント、ディレクティブ、パイプのみ。書いてはいけないのは


  • AppModule、 @NgModule 、サードパーティのモジュールのいずれの他のモジュールで既に宣言されているクラス

  • 他のモジュールからインポートされたディレクティブの配列(例: @angular/formsFORM_DIRECTIVES

  • モジュールクラス、サービスクラス

  • 非Angularのクラスやオブジェクト、文字列や数値などなど


Should I import BrowserModule or CommonModule?

ほとんど全てのブラウザアプリケーションのルートモジュール(AppModule)で

@angular/platform-browser からBrowserModuleをインポートすべき。

BrowserModuleはブラウザアプリケーションを起動して実行するのに必要なサービスをprovideする。

BrowserModuleは @angular/common のCommonModuleをre-exportしているので、NgIfやNgForといったディレクティブを使うことができる。

BrowserModuleを他のフィーチャーモジュールや遅延ロードされるモジュールからインポートしてはいけない。それらはかわりにCommonModuleをインポートすべきだ。共通のディレクティブは必要だが、アプリケーション全体のproviderを再度インストールする必要はない。


BrowserModuleを遅延ロードされるモジュールでインポートするとエラーが発生する


CommonModuleはブラウザだけではないターゲットプラットフォーム非依存のフィーチャーモジュールも提供する。


What if I import the same module twice?

問題ない。3つのモジュールがModuleAをインポートしたとき、AngularはModuleAが最初に出てきたときに一度だけ評価し、その後はしない。

これはインポートされたモジュールの階層でどのレベルAが表れても当てはまる(?)。ModuleBがModuleA,をインポートし、ModuleCがBを、ModuleDがC,B,Aをインポートし、DがCの評価を開始したとき、Bの評価が開始し、それがAを評価する。それからAngularがDでBとAを取得しようとするときは、既にキャッシュされている。

Angularは循環参照を持つモジュールは好きじゃないので、ModuleAがModuleBをインポートし、ModuleBがModuleAをインポートすることはないようにする。


What should I not export?

エクスポートするのはモジュールの外に公開するコンポーネント、ディレクティブ、パイプと、モジュール。エクスポートしてはいけないのは


  • プライベートはコンポーネント、ディレクティブ、パイプ

  • declareできないサービスや関数、オブジェクトなど

  • ルーターもしくはブートストラップで動的にロードされるだけのコンポーネント。こういったentry componentsは他のコンポーネントのテンプレートから使うことはできない。エクスポートしても害はないが、利益もない。

  • declarationをexportしていない純粋なサービスのモジュール。例えば、HttpModuleをre-exportしても意味はない。HttpModuleは何もexportしない。アプリケーション全体にHttpサービスproviderを追加する意味はある。


What is the forRoot method?

forRoot静的メソッドはモジュールのprovidersを設定するための慣例的なもの。

RouterModule.forRootはいい例で、RouterModule.forRootにRoutesオブジェクトを渡してアプリケーション全体のRouterサービスをルーティングとともに設定する。RouterModule.forRootはModuleWithProvidersを返す。それをAppModuleのimportsに加える。


.forRootの結果はアプリケーションのルートモジュールでのみimportする。他のモジュール、特に遅延ロードするモジュールでは、意図に反しているのでランタイムエラーが起きるかもしれない。

RouterModuleはforChild静的メソッドも持っていて、遅延ロードするモジュールのルーティングを設定できる。


forRootとforChildは慣例的な名前で、ルートとフィーチャーモジュールそれぞれでサービスを設定するメソッド名。

Angularはこの間違いは検出できないので開発者が気にする必要がある。


Why is a service provided in a feature module visible everywhere?

ブートストラップされたモジュールの @NgModule.providers に書いてあるprovidersはアプリケーションスコープを持つ。そこにサービスproviderを追加するとアプリケーション全体にサービスを共有する。

モジュールをインポートすると、Angularはそのモジュールのサービスprovider(そのモジュールの providers に入っているもの)をアプリケーションのルートインジェクターに追加する。

これはアプリケーションのどのクラスでもproviderのルックアップトークンがわかるのでproviderが見えるようになる。

これは意図的で、NgModuleシステムの一番の目的はモジュールインポートによる拡張性だ。モジュールproviderをアプリケーションのインジェクタにマージすることは、モジュールライブラリにとって新しいサービスでアプリケーション全体をより良くするのを簡単にする。HttpModuleを一度追加すれば、アプリケーションのどのコンポーネントからでもHttpリクエストを投げることができる。

しかし、モジュールのサービスがそのフィーチャーモジュールによって宣言されたコンポーネントからしか使えないと思った場合、これは想定外に感じるかもしれない。HeroModuleがHeroServiceをprovideしてルートのAppModuleがHeroModuleをインポートした場合、HeroModuleでdeclareされたクラスだけではなくすべてのクラスがHeroServiceをインジェクトして使うことができる。


Why is a service provided in a lazy-loaded module visible only to that module?

起動時にロードされたモジュールのproviderとは違い、遅延ロードされたモジュールのproviderはモジュールスコープになる。

Angularルーターがモジュールを遅延ロードしたとき、新たな実行コンテキストが作られる。そのコンテキストは自分のインジェクタを持っていて、アプリケーションインジェクタの直下の子になる。

ルーターはこの子インジェクタに遅延ロードされたモジュールのプロバイダと、そのモジュールがインポートしているモジュールのプロバイダを追加する。

これらのプロバイダは、同じルックアップトークンを持つアプリケーションプロバイダの変更から隔離される。ルータが遅延ロードされたコンテキスト内にコンポーネントを作成するとき、Angularはアプリケーションルートインジェクタのサービスインスタンスよりもこれらのプロバイダから作成されたサービスインスタンスを優先する。


What if two modules provide the same service?

2つのインポートされたモジュールが同時に読み込まれ、同じトークンを持つプロバイダをリストすると、2番目のモジュールのプロバイダが「勝利」します。 両方のプロバイダが同じインジェクタに追加されているからです。

Angularは、そのトークンのサービスを挿入するように見えるときに、2番目のプロバイダによって作成されたインスタンスを作成して配信します。

このサービスを注入するすべてのクラスは、2番目のプロバイダによって作成されたインスタンスを取得します。 最初のモジュールで宣言されたクラスでも、2番目のプロバイダによって作成されたインスタンスが取得されます。

モジュールAがトークン「X」のサービスを提供し、トークン「X」のサービスも提供するモジュールBをインポートする場合、モジュールAのサービス定義は「勝つ」。

ルートAppModuleによって提供されるサービスは、インポートされたモジュールによって提供されるサービスよりも優先されます。 AppModuleは常に勝ちます。


How do I restrict service scope to a module?

アプリケーション起動時にモジュールがロードされると、その @NgModule.providers はアプリケーション全体のスコープになる。つまり、アプリケーション全体にインジェクトすることができる。


一般的なルールとして、providersのあるモジュールは一度だけ、より好ましいのはアプリケーションのルートモジュールにインポートする。普通はこれがモジュールを設定、ラップ、上書きするのに最適な場所となる。


すべてのHttpリクエストに特別なヘッダを追加するカスタマイズされたHttpBackendを必要とするモジュールがあるとする。アプリケーションの他のモジュールが同様にHttpBackendをカスタマイズしたり、単にHttpModuleをインポートすると、それはこのモジュールのHttpBackendプロバイダを上書きするかもしれず、特別なヘッダがつかなくなる。

この問題を避けるために、HttpModuleはアプリケーションのルートのAppModuleでのみインポートする。

このようなprovider汚染を防ぎたい場合は起動時のモジュールのproviderに依存してはいけない。

できるならモジュールを遅延ロードする。Angularは遅延ロードされたモジュールにそれ用の子インジェクタを与える。そのモジュールのproviderはこのインジェクタで作成されたコンポーネントツリーの中からのみ見える。

即時ロードしなければいけない場合は、アプリケーションが開始したときに、コンポーネントにサービスをprovideする。

同じ例を続けると、モジュールにあるコンポーネントが本当にプライベートのカスタムHttpBackendを必要すると仮定する。

モジュールの全てのコンポーネントのルートとして振る舞うトップコンポーネントを作成する。カスタムHttpBackendをそのトップコンポーネントのprovidersに入れる。Moduleのprovidersではない。Angularはコンポーネントインスタンスごとに子インジェクタを作成し、コンポーネントのproviderにそのインジェクタを設定することを思い出す。

このコンポーネントの子がHttpBackendサービスを要求したとき、Angularはアプリケーションのルートインジェクタがprovideするものではない、ローカルなHttpBackendサービスをprovideする。子コンポーネントは他のモジュールがHttpBackendに何をしても関係なく、正しいHttpリクエストを送れる。

このモジュールのトップコンポーネントの子になるようにコンポーネントを作る。

トップコンポーネントのテンプレートに子コンポーネントを埋め込むことができる。または、 <router-outlet> を指定してトップコンポーネントをルーティングのホストにする。子コンポーネントを定義し、ルータにそのルーターアウトレットの中にコンポーネントをロードさせる。


Should I add application-wide providers to the root AppModule or the root AppComponent?

アプリケーション全体のプロバイダをAppComponentではなく、ルートのAppModuleに登録します。

遅延ロードされたモジュールとそのコンポーネントは、AppModuleサービスを注入できます。 AppComponentサービスを注入することはできません。

AppComponentツリーの外部のコンポーネントからサービスを非表示にする必要がある場合のみ、AppComponentプロバイダにサービスを登録します。まれな使用例です。

より一般的には、コンポーネントよりもモジュールのprovidersに登録することをお勧めします。


Discussion

Angularは、すべての起動モジュールプロバイダをアプリケーションルートインジェクタに登録します。ルートインジェクタプロバイダから作成されたサービスは、アプリケーション全体で使用できます。それらはアプリケーションスコープです。

特定のサービス(ルーターなど)は、アプリケーションルートインジェクタに登録されている場合にのみ機能します。

対照的に、AngularはAppComponentのプロバイダにAppComponentのインジェクタを登録します。 AppComponentサービスは、そのコンポーネントとそのコンポーネントツリーでのみ使用できます。それらはコンポーネントスコープです。

AppComponentのインジェクタは、ルートインジェクタの子であり、インジェクタ階層内にあります。ルーターを使用しないアプリケーションの場合は、ほとんどすべてのアプリケーションです。しかし、ルーティングされたアプリケーションの場合、「ほとんど」は十分ではありません。

AppComponentサービスは、ルーティングが動作するルートレベルに存在しません。遅延ロードモジュールはそれらに到達できません。 NgModuleページのサンプルアプリケーションで、AppComponentにUserServiceを登録していた場合、HeroComponentはそれを注入できませんでした。ユーザーが「ヒーローズ」にナビゲートした瞬間、アプリケーションは失敗します。


Should I add other providers to a module or a component?

一般に、機能固有のプロバイダはコンポーネント(@ Component.providers)に登録するよりもモジュール(@ NgModule.providers)にを登録することをお勧めします。

サービスインスタンスのスコープをそのコンポーネントとそのコンポーネントツリーに限定する必要がある場合は、プロバイダをコンポーネントに登録します。 ディレクティブのプロバイダーに登録するのも同じ理由です。

たとえば、キャッシングヒーローサービスのプライベートコピーが必要なヒーロー編集コンポーネントは、HeroServiceをHeroEditorComponentに登録する必要があります。 その後、HeroEditorComponentの新しいインスタンスはそれぞれ独自のキャッシュされたサービスインスタンスを取得します。 編集者がサービスでヒーローに加えた変更は、アプリケーションの他の場所のヒーローのインスタンスには触れません。

アプリケーション全体のサービスは、常にルートAppComponentではなく、ルートAppModuleに登録してください。


Why is it bad if SharedModule provides a service to a lazy-loaded module?

この質問は、NgModulesページの「UserServiceが共有されない理由」セクションで扱われています。ここでは、プロバイダをSharedModuleから外すことの重要性について説明しています。

UserServiceがSharedModuleのプロバイダにリストされていて、すべてのモジュールがこのSharedModuleをインポートしたとします。

アプリケーションが起動すると、AngularはAppModuleとContactModuleを即時に読み込みます。

インポートされたSharedModuleの両方のインスタンスがUserServiceを提供します。 Angularは、ルートアプリインジェクタの1つを登録します(What if I import the same module twice?を参照)。次に、あるコンポーネントがUserServiceを注入し、Angularがそれをアプリケーションルートインジェクタで見つけ出し、アプリ全体のシングルトンUserServiceを配信します。問題ない。

今、遅延ロードされているHeroModuleについて考えてみましょう。

ルータはHeroModuleを遅延ロードすると、子インジェクタを作成し、その子インジェクタにUserServiceプロバイダを登録します。子インジェクタはルートインジェクタではありません。

Angularが遅延ロードされるHeroComponentを作成するとき、それはUserServiceを注入する必要があります。今回は、遅延モジュールの子インジェクタでUserServiceプロバイダを見つけて、UserServiceの新しいインスタンスを作成します。これは、即時読み込みされたコンポーネントにAngularが挿入した、アプリ全体のシングルトンのサービスとは全く異なるUserServiceインスタンスです。

それはほとんどの場合で間違いです。


デモを行うには、ライブのサンプル/ダウンロードのサンプルを実行します。 CoreModuleではなくUserServiceを提供するようにSharedModuleを変更します。次に、「連絡先」リンクと「ヒーローズ」リンクを数回切り替えます。 Angularは毎回新しいUserServiceインスタンスを作成するため、ユーザー名は不公平になります。



Why does lazy loading create a child injector?

Angularは、モジュールが遅延ロードされていない限り、@ NgModule.providersをアプリケーションルートインジェクタに追加します。遅延ロードモジュールの場合、Angularは子インジェクタを作成し、子インジェクタにモジュールのプロバイダを追加します。

これは、モジュールがアプリケーションの起動中にロードされるか、遅延ロードされるかによって、動作が異なることを意味します。その違いを無視することは悪影響をもたらす可能性があります。

Angularは、即時に読み込まれたモジュールと同じように、遅延ロードされたプロバイダをアプリのルートインジェクタに追加しないのはなぜでしょう?

答えは、AngularのDIシステムの基本的な特性に基づいています。インジェクタは、最初に使用されるまでプロバイダを追加できます。インジェクタがサービスの作成と配信を開始すると、プロバイダのリストはフリーズされます。新しいプロバイダは許可されません。

アプリケーションが起動すると、Angularは、最初のコンポーネントを作成し、提供されたサービスのいずれかを注入する前に、即時に読み込まれたすべてのモジュールのプロバイダを使用してルートインジェクタを最初に設定します。アプリケーションが開始されると、アプリケーションルートインジェクタは新しいプロバイダに対して閉じられます。

時間が経過し、アプリケーションロジックがモジュールの遅延ロードをトリガします。 Angularは、遅延ロードされたモジュールのプロバイダをどこかのインジェクタに追加する必要があります。そのインジェクタは新しいプロバイダに対して閉じられているため、アプリのルートインジェクタには追加できません。したがって、Angularは、遅延ロードされたモジュールコンテキスト用の新しい子インジェクタを作成します。


How can I tell if a module or service was previously loaded?

一部のモジュールとそのサービスは、ルートAppModuleによって一度だけロードされる必要があります。 モジュールを遅延ロードすることによってモジュールを2回目にインポートすると、検出して診断するのが困難な誤った動作が発生する可能性があります。

この問題を回避するには、ルートアプリインジェクタからモジュールまたはサービスを注入しようとするコンストラクタを作成します。 注入が成功すると、クラスは2回目にロードされます。 エラーを投げたり、他の是正措置を講じることができます。

特定のNgModule(BrowserModuleなど)は、NgModulesページのこのCoreModuleコンストラクタなどのガードを実装します。


src/app/core/core.module.ts

constructor (@Optional() @SkipSelf() parentModule: CoreModule) {

if (parentModule) {
throw new Error(
'CoreModule is already loaded. Import it in the AppModule only');
}
}


What is an entry component ?

エントリコンポーネントは、Angularが型によって明示的にロードするコンポーネントです。

セレクタを介して宣言的にロードされたコンポーネントは、エントリコンポーネントではありません。

ほとんどのアプリケーションコンポーネントは宣言的にロードされます。角度は、コンポーネントのセレクタを使用してテンプレート内の要素を検索します。次に、コンポーネントのHTML表現を作成し、選択した要素のDOMに挿入します。これらはエントリーコンポーネントではありません。

いくつかのコンポーネントは動的にロードされるだけで、コンポーネントテンプレートで参照されることはありません。

ブートストラップされたルートAppComponentはエントリコンポーネントです。実際、セレクタはindex.htmlの要素タグと一致します。しかし、index.htmlはコンポーネントテンプレートではなく、AppComponentセレクタはどのコンポーネントテンプレートの要素とも一致しません。

Angularは、@ NgModule.bootstrapの型がリストされているか、またはモジュールのngDoBootstrapメソッドを使用して強制的にboostrappされているため、AppComponentを動的にロードします。

ルート定義内のコンポーネントもエントリコンポーネントです。ルート定義は、コンポーネントをその型ごとに参照します。ルータは、ルーティングされたコンポーネントのセレクタ(それがある場合でも)を無視し、そのコンポーネントをRouterOutletに動的にロードします。

コンパイラは、これらのエントリコンポーネントを他のコンポーネントテンプレートで検索することでこれらのエントリコンポーネントを検出することはできません。あなたは、それらをentryComponentsリストに追加することによってそれらについて伝える必要があります。

Angularは、次のタイプのコンポーネントをモジュールのentryComponentsに自動的に追加します。


  • @ NgModule.bootstrapリストのコンポーネント

  • ルータ構成で参照されるコンポーネント


What kinds of modules should I have and how should I use them?

すべてのアプリは異なっています。開発者は、さまざまなレベルの経験と快適さを利用できる選択肢を持っています。いくつかの提案とガイドラインには、幅広い魅力があります。


以下は、いくつかのアプリケーションでNgModuleを使用した初期の経験に基づく予備的なガイダンスです。適切な注意と熟考を持って読んでください。



SharedModule

アプリケーション内のどこでも使用するコンポーネント、ディレクティブ、およびパイプを使用してSharedModuleを作成します。このモジュールは完全に宣言で構成され、そのほとんどはエクスポートされます。

SharedModuleは、CommonModule、FormsModule、および最も広く使用するUIコントロールを持つモジュールなど、他のウィジェットモジュールを再エクスポートすることがあります。

SharedModuleには、以前に説明した理由でプロバイダが存在してはなりません。同様にimportされたモジュールまたはre-exportされたモジュールのいずれにもプロバイダがあってはいけません。このガイドラインから逸脱した場合、あなたがやっていることとその理由を知ってください。

SharedModuleは、即時ロード・遅延ロードの両方のフィーチャーモジュールにインポートします。


CoreModule

アプリケーションの起動時にロードするシングルトンサービスのプロバイダを持つCoreModuleを作成します。

CoreModuleをルートAppModuleでのみインポートします。ほかのモジュールでCoreModuleをインポートしないでください。

CoreModuleをdeclarationsのない純粋なサービスモジュールにすることを検討してください。


このページサンプルは、AppModuleによって宣言されたルートAppComponent内でのみ使用される2つのコンポーネントを宣言してエクスポートすることによって、そのアドバイスからはずれています。このガイドラインに従う人は、これらのコンポーネントをAppModuleに厳密に宣言しています。



Feature Module

特定のアプリケーションビジネスドメイン、ユーザーワークフロー、およびユーティリティコレクションに関する機能モジュールを作成します。

フィーチャモジュールは、次のグループのいずれかに分類されます。


現実世界のモジュールは、しばしば以下のガイドラインから意図的に逸脱したハイブリッドです。 これらのガイドラインは法律ではありません。 そうしなければならない正当な理由がない限り、それらに従ってください。



Domain feature modules

ドメイン機能モジュールは、顧客の編集や発注など、特定のアプリケーションドメイン専用のユーザーエクスペリエンスを提供します。

これらは通常、機能のルートとして機能するトップコンポーネントを持っています。 プライベートなサブコンポーネントを子に持っています。

ドメインフィーチャモジュールは主にdeclarationsで構成されています。一番上のコンポーネントだけがエクスポートされます。

ドメインフィーチャーモジュールにはプロバイダはほとんどありません。 彼らが行うとき、提供されたサービスの寿命は、モジュールの寿命と同じでなければなりません。

ドメイン機能モジュールにアプリケーション全体のシングルトンサービスを提供しないでください。

ドメインフィーチャモジュールは、通常、より大きなフィーチャモジュールによって一度だけインポートされます。

彼らはルーティングがあまりない小さなアプリケーションのルートAppModuleによってインポートされる場合もあります。


たとえば、ルーティングを導入する前に、「NgModules」ページのMake Contact a feature moduleセクションを参照してください。



Routed feature modules

ルーテッド・フィーチャー・モジュールは、ドメイン・フィーチャー・モジュールであり、上位コンポーネントがルーター・ナビゲーション・ルートのターゲットです。

すべての遅延ロードされたモジュールは、定義された機能モジュールにルーティングされます。

このページのContactModule、HeroModule、およびCrisisModuleは、ルーティングされた機能モジュールです。

ルーテッドフィーチャモジュールは何もエクスポートしません。これらのコンポーネントは、外部コンポーネントのテンプレートに決して表示されないため、必要ありません。

遅延ロードされたルーテッドフィーチャモジュールは、どのモジュールでもインポートすることはできません。それをすると、即時ロードが引き起こされてしまい遅延ロードされません。 HeroModuleとCrisisModuleは遅延ロードされます。それらはAppModuleのインポートのリストに入っていません。

しかし、即時ロードされたルーテッドフィーチャーモジュールは、コンパイラーがそのコンポーネントについて学習するために、別のモジュールによってインポートされなければなりません。 ContactModuleは即時ロードされ、AppModuleのインポートにリストされます。

ルーテッドフィーチャモジュールは、以前に説明した理由でプロバイダを持つことはめったにありません。彼らが行うとき、提供されたサービスの寿命は、モジュールの寿命と同じでなければなりません。

ルーテッド機能モジュールまたはルーテッドモジュールがインポートするモジュールにアプリケーション全体のシングルトンサービスを提供しないでください。


Routing modules

ルーティングモジュールは、別のモジュールのルーティング設定を提供します。

ルーティングモジュールは、ルーティングの関心をそのモジュールから分離します。

ルーティングモジュールは、通常、次の処理を行います。


  • ルートを定義します。

  • モジュールのインポートにルータ設定を追加します。

  • RouterModuleを再エクスポートします。

  • guardとresolverのサービスプロバイダをモジュールのプロバイダに追加します。

ルーティングモジュールの名前は、接尾辞 "Routing"を使用して、その対象とするモジュールの名前に対応する必要があります。たとえば、foo.module.tsのFooModuleには、foo-routing.module.tsにFooRoutingModuleという名前のルーティングモジュールがあります。

対象とするモジュールがルートAppModuleである場合、AppRoutingModuleは

RouterModule.forRoot(routes) を使用してそのインポートにルータ設定を追加します。他のすべてのルーティングモジュールは、 RouterModule.forChild(routes) をインポートする子です。

ルーティングモジュールは、対象とするモジュールのコンポーネントがRouterLinkやRouterOutletなどのルータディレクティブにアクセスできるように、RouterModuleを再エクスポートします。

ルーティングモジュールはそれ自身のdeclarationsを持つべきではありません。コンポーネント、ディレクティブ、およびパイプは、ルーティングモジュールではなく、フィーチャモジュールの役割を担います。

ルーティングモジュールは、その対象とするモジュールによってのみインポートする必要があります。

AppRoutingModule、ContactRoutingModule、およびHeroRoutingModuleは良い例です。


Routing&NavigationページのDo you need a Routing Module?も参照してください。



Service feature modules

サービスモジュールは、データアクセスやメッセージングなどのユーティリティサービスを提供します。

理想的には、それらは完全にプロバイダで構成され、declarationsはありません。 CoreModuleとAngularのHttpModuleは良い例です。

サービスモジュールは、ルートAppModuleによってのみインポートされる必要があります。

他の機能モジュールでサービスモジュールをインポートしないでください。 このガイドラインから逸脱した場合、あなたがやっていることとその理由を知ってください。


Widget feature modules

ウィジェットモジュールは、コンポーネント、ディレクティブ、およびパイプを外部モジュールで使用できるようにします。

CommonModuleとSharedModuleはウィジェットモジュールです。 多くのサードパーティのUIコンポーネントライブラリは、ウィジェットモジュールです。

ウィジェットモジュールは宣言から完全に構成され、そのほとんどはエクスポートされます。

ウィジェットモジュールはプロバイダを持つことはほとんどありません。 このガイドラインから逸脱した場合、あなたがやっていることとその理由を知ってください。

コンポーネントテンプレートにウィジェットが必要なモジュールのウィジェットモジュールをインポートします。

次の表は、各フィーチャモジュールグループの主要な特性をまとめたものです。


実世界のモジュールは、しばしばこれらのガイドラインから逸脱したハイブリッドです。


Feature Module
Declarations
Providers
Exports
Imported By
Examples

Domain
Yes
Rare
Top component
Feature, AppModule

ContactModule (before routing)

Routed
Yes
Rare
No
Nobody

ContactModule , HeroModule , CrisisModule

Routing
No
Yes (Guards)
RouterModule
Feature (for routing)

AppRoutingModule , ContactRoutingModule , HeroRoutingModule

Service
No
Yes
No
AppModule

HttpModule , CoreModule

Widget
Yes
Rare
Yes
Feature

CommonModule , SharedModule


How does Angular find components, directives, and pipes in a template? What is a template reference?

Angularコンパイラは、他のコンポーネント、ディレクティブ、およびパイプのコンポーネントテンプレートを調べます。 それが見つかると、それは "テンプレート参照"です。

Angularコンパイラは、そのコンポーネントのセレクタまたはディレクティブをそのテンプレートの一部のHTMLに一致させることができるときに、テンプレート内のコンポーネントまたはディレクティブを見つけます。

パイプの名前がテンプレートHTMLのパイプ構文内に現れた場合、コンパイラはパイプを検出します。

Angularは、このモジュールによって宣言された、またはこのモジュールがインポートするモジュールによってエクスポートされたクラスのセレクタおよびパイプ名にのみ一致します。


What is the Angular compiler?

Angularコンパイラは、作成したアプリケーションコードを高性能のJavaScriptコードに変換します。 @NgModuleメタデータは、コンパイルプロセスの指針として重要な役割を果たします。

あなたが書いたコードは即座に実行可能ではありません。コンポーネントを例にします。コンポーネントには、カスタム要素、属性ディレクティブ、Angularのバインディング、および固有のHTMLではない固有の構文が含まれているテンプレートがあります。

Angularコンパイラは、テンプレートマークアップを読み取り、対応するコンポーネントクラスコードと結合し、コンポーネントファクトリを発行します。

コンポーネントファクトリは、@Component メタデータに記述されているすべての要素(HTML、バインディング命令、添付されたスタイル)を組み込んだ、コンポーネントの純粋な100%JavaScript表現を作成します。

ディレクティブとパイプはコンポーネントテンプレートに表示されるため、Angularコンパイラはコンパイルされたコンポーネントコードにもそれらを組み込みます。

@NgModuleメタデータは、Angularコンパイラに、このモジュール用にコンパイルするコンポーネントと、このモジュールを他のモジュールとリンクする方法を指示します。


NgModule API

次の表は、NgModuleメタデータのプロパティをまとめたものです。


declarations

宣言可能なクラス、コンポーネント、ディレクティブ、およびこのモジュールに属するパイプクラスのリスト。

これらの宣言されたクラスはモジュール内で可視ですが、このモジュールからエクスポートされ、他のモジュールがこのモジュールをインポートしない限り、別のモジュール内のコンポーネントには表示されません。

コンポーネント、ディレクティブ、およびパイプは、正確に1つのモジュールに属している必要があります。 複数のモジュールで同じクラスを宣言しようとすると、コンパイラでエラーが発生します。

別のモジュールからインポートしたクラスを再宣言しないでください。


providers

依存性注入プロバイダのリスト。

Angularは、これらのプロバイダをモジュールの実行コンテキストのルートインジェクタに登録します。これは、アプリケーションの起動時にロードされるすべてのモジュールのアプリケーションのルートインジェクタです。

Angularは、これらのプロバイダサービスの1つをアプリケーションの任意のコンポーネントに挿入できます。このモジュールまたは起動時にロードされたモジュールがHeroServiceを提供する場合、Angularは同じHeroServiceインテンシブを任意のアプリケーションコンポーネントに注入できます。

遅延ロードされたモジュールには、通常アプリケーションルートインジェクタの直接の子である独自のサブルートインジェクタがあります。

遅延ロードされたサービスは、レイジーモジュールのインジェクタにスコープされます。レイジーロードされたモジュールもHeroServiceを提供する場合、そのモジュールのコンテキスト内で作成されたコンポーネント(ルータのナビゲーションなど)は、ルートアプリケーションインジェクタのインスタンスではなく、サービスのローカルインスタンスを取得します。

外部モジュールのコンポーネントは、引き続きアプリケーションルート用に作成されたインスタンスを受け取ります。


imports

サポートするモジュールのリスト。

具体的には、エクスポートされたコンポーネント、ディレクティブ、またはパイプが、このモジュールで宣言されたコンポーネントテンプレートによって参照されるモジュールのリスト。

コンポーネントテンプレートは、参照されたクラスがこのモジュールで宣言されているか、そのクラスが別のモジュールからインポートされたときに、別のコンポーネント、ディレクティブ、またはパイプを参照できます。

コンポーネントはNgIfおよびNgForディレクティブを使用できます。これは、その親モジュールが(おそらくはBrowserModuleをインポートして間接的に)Angular CommonModuleをインポートしたためです。

CommonModuleを使用して多くの標準ディレクティブをインポートできますが、使い慣れたディレクティブは他のモジュールに属しています。コンポーネントテンプレートは、角度FormsModuleをインポートした後でのみ[(ngModel)]とバインドできます。


exports

インポートモジュールが使用できる宣言のリスト(コンポーネント、ディレクティブ、パイプクラス)。

エクスポートされた宣言は、モジュールの公開APIです。別のモジュールのコンポーネントは、このモジュールをインポートするとこのモジュールのHeroComponentを参照でき、このモジュールはHeroComponentをエクスポートします。

宣言はデフォルトではプライベートです。このモジュールがHeroComponentをエクスポートしない場合、他のモジュールはHeroComponentを見ることができません。

モジュールをインポートしても、インポートされたモジュールのインポートは自動的に再エクスポートされません。モジュール 'B'は、CommonModuleをインポートしたモジュールAをインポートしただけなのでngIfを使用できません。モジュール 'B'はCommonModule自体をインポートする必要があります。

モジュールはエクスポートの間に別のモジュールをリストすることができます。その場合、そのモジュールのパブリックコンポーネント、ディレクティブ、およびパイプがすべてエクスポートされます。

再輸出はモジュールの推移を明示的にする。モジュール 'A'がCommonModuleを再エクスポートし、モジュール 'B'がモジュール 'A'をインポートする場合、 'B'自体がCommonModuleをインポートしなくても、モジュール 'B'コンポーネントはngIfを使用できます。


bootstrap

ブートストラップ可能なコンポーネントのリスト。

通常、このリストにはアプリケーションのルートコンポーネントが1つしかありません。

Angularは複数のブートストラップコンポーネントで起動することができ、それぞれはホストWebページ内に独自の場所を持ちます。

ブートストラップコンポーネントは自動的にentryComponentです。


entryComponents

到達可能なコンポーネントテンプレートで参照されていないコンポーネントのリスト。

ほとんどの開発者はこのプロパティを設定しません。 Angularコンパイラは、アプリケーションで実際に使用されるすべてのコンポーネントについて知っている必要があります。コンパイラは、参照のツリーを1つのコンポーネントテンプレートから別のコンポーネントテンプレートに移動することによって、ほとんどのコンポーネントを検出できます。

しかし、常にテンプレートの中で参照されていないコンポーネントが少なくとも1つあります:ルートコンポーネント、AppComponentは、あなたがアプリケーションを起動するためにブートストラップします。それがエントリーコンポーネントと呼ばれる理由です。

ルーティングされたコンポーネントもテンプレートで参照されないため、エントリコンポーネントです。ルータはそれらを作成し、の近くのDOMにドロップします。

ブートストラップされルーティングされたコンポーネントはエントリコンポーネントですが、通常、それらをモジュールのentryComponentsリストに追加する必要はありません。

Angularは、モジュールのブートストラップリスト内のコンポーネントを自動的にentryComponentsリストに追加します。 RouterModuleは、ルーティングされたコンポーネントをそのリストに追加します。

それは発見できないコンポーネントの次のソースだけを残します:

コンポーネントは、命令的手法の1つを使用してブートストラップされました。コンポーネントはルータ以外の何らかの手段でDOMに動的にロードされます。

どちらも高度な技術であり、ほとんどの開発者がこれまで使用していません。これらのコンポーネントの数が少ない場合は、これらのコンポーネントをプログラマチックにまたは手作業でentryComponentsリストに追加する必要があります。