アングル・アーキテクチャ
17556 ワード
前の記事では、コマンドパターンを使用してスケーラブルな方法でコンテキストメニューのアクション定義を格納することについて書きました
この記事を終了した後に簡単にスケーラブルであり、互いに独立しているとアプリの残りの対話の数十を管理する方法を知られているでしょう.
ショーケースアプリケーションのダイアログシーケンスを示すGIF
記事へのリンク
問題
モジュールを持っています. コンポーネントを持っています. データ入力モデル構造を持ちます. これまでのところ良い.角材を用いた対話を示す
角度がインスタンス化するために
表情で
ダイアログを持つダイアログデータインターフェイスに自動的に一致するメソッドが必要です.
解決策
ComponentType -ダイアログクラス DataType -ダイアログがそのオープナーから受け取る構造. 返り値-構造体がそのオープナーに戻ります. また、それを注釈する必要があります
1つの抽象メソッドもあります. ベースクラスを作成した後に
魔法の部分は
注:使用
以下の例では、アクションをクリックしたときのみモジュールファイルがフェッチされます.
予想外の問題
だから
それでは、どのように修正することができますか?
まず、値と型の違いを理解する必要があります.
以下の例では、クラスを値として使用します.これはJavaScriptにコンパイルした後にまだ存在します.
以下の例では、クラスを型として使用します.これは、JavaScriptからすべてのインポートを完全に削除することを意味します.
コンポーネントの遅延読み込み
専用のモジュールを持っています. 専用コンポーネントです. 専用のデータ入力構造を持ちます. 専用のasyncサービスを持っています. 我々は今我々のアプリに50以上のダイアログを追加し、それらのすべてを使用して1つのビューのいずれもすぐに来るだろう.それはいくつかのケースでは、同時に2つのMBのライブラリを使用して、バイオリンを再生するときに便利です.結果が結果としてそれをすべてダウンロードする正しい行動を引き起こすまで、ビューはスリムで軽いでしょう.
github repoはstackblitzと同様に以下のようになります.
結論
ActionService
🎉). ショーケースアプリケーションでは、熱心にロードされたダイアログを使用しました.これは、すべてのダイアログモジュールがブラウザにダウンロードされていることを意味します.それを修正しましょう!この記事を終了した後に簡単にスケーラブルであり、互いに独立しているとアプリの残りの対話の数十を管理する方法を知られているでしょう.
ショーケースアプリケーションのダイアログシーケンスを示すGIF
![](https://s1.md5.ltd/image/bcdb10e47aef716c5a40f77fd987ceb2.gif)
記事へのリンク
![](https://s1.md5.ltd/image/ff32b849275958c357f0b8d3faf0a7ab.png)
大量のコンテキストメニューアクションを管理するコマンドパターンの使用方法
マケジサキキ・ Nov 9・ 8分読
#angular
#typescript
#javascript
#beginners
問題
現在、ダイアログの構造は次のようになります.
各ダイアログ:
MatDialog
サービスconstructor(private matDialog: MatDialog) {
const dialogData: JobUserAssignDialogDataModel = {
jobId: params.jobId,
};
this.matDialog
.open(JobUserAssignDialogComponent, {data: dialogData})
}
残念ながら、このアプローチには2つの問題があります.1 .すべてのダイアログはappmoduleでバンドルされます
角度がインスタンス化するために
JobUserAssignDialogComponent
それはどこかで宣言される必要がありますJobUserAssignDialogModule
また、それをインポートする必要がありますAppModule
:@NgModule({
declarations: [
AppComponent
],
imports: [
...,
JobUserAssignDialogModule,
ConfirmationDialogModule
],
bootstrap: [AppComponent]
})
export class AppModule { }
今、すべてのダイアログがバンドルされてmain.js
ファイルは、ユーザーがすべてのそれらを使用していないページ上にある場合でも、それらをすべてダウンロードする結果!2 .対話データの静的な型強制
表情で
.open(JobUserAssignDialogComponent, {data: dialogData})
the data
フィールドにはany
指定された型を手動で指定するまで.これは非常にエラーがちなのは、非常に簡単に何かをするか、まったく何かを入力するのは簡単です.ダイアログを持つダイアログデータインターフェイスに自動的に一致するメソッドが必要です.
解決策
前の記事からのアクション定義の場合と同じように、各ダイアログモジュールごとにダイアログサービスをするのは賢明です.
まず、ダイアログサービスの基本クラスを作成します.
@Directive()
// tslint:disable-next-line:directive-class-suffix
export abstract class AsyncDialog<ComponentType, DataType, ReturnType = unknown> {
constructor(protected matDialog: MatDialog) {
}
abstract async open(data: DataType): Promise<MatDialogRef<ComponentType, ReturnType>>;
}
このクラスはほとんど一貫性を保つためです.
The AsyncDialog
クラスは3つの一般的なパラメータを消費します:
@Directive()
// tslint:disable-next-line:directive-class-suffix
export abstract class AsyncDialog<ComponentType, DataType, ReturnType = unknown> {
constructor(protected matDialog: MatDialog) {
}
abstract async open(data: DataType): Promise<MatDialogRef<ComponentType, ReturnType>>;
}
@Directive()
, バージョン10以降では、デコレータなしでクラスのコンストラクタパラメータからすべての型を削除しますMatDialog
.1つの抽象メソッドもあります.
open()
- ダイアログを開くためのテンプレートJobUserAssignDialogService
:@Injectable({providedIn: 'root'})
export class JobUserAssignDialogService extends AsyncDialog<JobUserAssignDialogComponent, JobUserAssignDialogDataModel, UserModel> {
async open(data: JobUserAssignDialogDataModel): Promise<MatDialogRef<JobUserAssignDialogComponent, UserModel>> {
// the magical part of importing a module asynchronously
await import('../job-user-assign-dialog.module');
return this.matDialog.open(JobUserAssignDialogComponent, {data});
}
}
The JobUserAssignDialogService
から継承するAsyncDialog
以前に作成された基底クラス.3つのジェネリックパラメーターでは、このサービスがどのコンポーネントに対して責任があるか、何が消費されているか、何が返されるかを指定します.魔法の部分は
await import('...')
. これは、まだダウンロードされていない場合は、モジュールファイルを取得する角度を伝えます.その後、私たちはちょうど前に行ったようにダイアログを開きます.注:使用
async
キーワードは、非同期のインポートが約束を返すので、操作が完了するまでダイアログを開くと待機する必要があります.以下の例では、アクションをクリックしたときのみモジュールファイルがフェッチされます.
![](https://s1.md5.ltd/image/e226c505633bbc3fb6e7cd2b1d908ec4.gif)
予想外の問題
GIFは、ダイアログモジュールが非同期にフェッチされていることを示しますng build
のソースコードを詳しく見てくださいJobListViewComponent
我々は見つけることができますJobUserAssignDialogComponent
代わりに怠惰なモジュールのアプリにバンドルされています.
何を待つ?
ダイアログコンポーネントは怠惰に読み込まれてはいけませんか?我々はちょうど怠惰にモジュールをダウンロードしている!何が起こっている!
...
この動作を行う行は、ダイアログを開く行です.でもどうして?
@Injectable({providedIn: 'root'})
export class JobUserAssignDialogService extends AsyncDialog<...> {
async open(data: JobUserAssignDialogDataModel): Promise<...> {
await import('../job-user-assign-dialog.module');
// THIS IS THE CULPRIT!
return this.matDialog.open(JobUserAssignDialogComponent, {data});
}
}
依存グラフ
インポート連鎖を解析した場合(何をインポートするか)、次のグラフを描画できます.
ビューのジョブビューでは、アクションを呼び出してダイアログに3つのインポートがあります.
@Injectable({providedIn: 'root'})
export class JobUserAssignDialogService extends AsyncDialog<...> {
async open(data: JobUserAssignDialogDataModel): Promise<...> {
await import('../job-user-assign-dialog.module');
// THIS IS THE CULPRIT!
return this.matDialog.open(JobUserAssignDialogComponent, {data});
}
}
JobsComponent
注射するJobAssignAction
そして、値としてタイプを使用します(角度はコンストラクタparamsのタイプを保存します、そうすれば、何を注入するかについてわかっています).JobAssignAction
注射するJobUserAssignDialogService
また、値として型を使用します.JobUserAssignDialogService
オープンJobUserAssignDialogComponent
として、その型を値として使用します.JobsComponent
角度で走らせるには、JobUserAssignDialogComponent
, すべての道に沿ってそれは値として使用された!それでは、どのように修正することができますか?
値対型の使用
まず、値と型の違いを理解する必要があります.
値として
以下の例では、クラスを値として使用します.これはJavaScriptにコンパイルした後にまだ存在します.
// typescript
const componentClass = JobUserAssignDialogComponent;
// javascript
const componentClass = JobUserAssignDialogComponent;
種類として
以下の例では、クラスを型として使用します.これは、JavaScriptからすべてのインポートを完全に削除することを意味します.
// typescript
const component: JobUserAssignDialogComponent = {};
// javascript
const component = {};
コンポーネントの遅延読み込み
今、私たちはどういうわけかJobUserAssignDialogComponent
値として、値としてインポートせずに.我々は、我々はlazilyいくつかの助けをインポートインポートすることができます!
@NgModule({
declarations: [JobUserAssignDialogComponent],
imports: [...],
})
export class JobUserAssignDialogModule {
static getComponent(): typeof JobUserAssignDialogComponent {
return JobUserAssignDialogComponent;
}
}
現在、コンポーネントを値としてインポートするモジュールの責任は、静的メソッドをgetComponent()
, そして、我々にそれを返してください.
その後、ダイアログサービスを調整できます.
@Injectable({providedIn: 'root'})
export class JobUserAssignDialogService extends AsyncDialog<JobUserAssignDialogComponent,...> {
async open(data: JobUserAssignDialogDataModel): Promise<MatDialogRef<...> {
const importedModuleFile = await import('../job-user-assign-dialog.module');
// the `importedModuleFile` has all the imports of the file
// and since one of them is `JobUserAssignDialogModule`
// we can use it to invoke previously defined `getComponent()` method
return this.matDialog.open(
importedModuleFile.JobUserAssignDialogModule.getComponent(),
{data},
);
}
}
ET Vil il!ダイアログコンポーネントは、現在Lazzilyロードされているモジュールとバンドルされています.
ジェネリックパラメーターとして使用するコンポーネントクラスについてはAsyncDialog<JobUserAssignDialogComponent,...>
? 幸運にも、それはタイプとして使用され、コンパイルフェーズで完全に削除されます.
最終プロジェクト構造
scructureは次のようになります.
各ダイアログ:
@NgModule({
declarations: [JobUserAssignDialogComponent],
imports: [...],
})
export class JobUserAssignDialogModule {
static getComponent(): typeof JobUserAssignDialogComponent {
return JobUserAssignDialogComponent;
}
}
@Injectable({providedIn: 'root'})
export class JobUserAssignDialogService extends AsyncDialog<JobUserAssignDialogComponent,...> {
async open(data: JobUserAssignDialogDataModel): Promise<MatDialogRef<...> {
const importedModuleFile = await import('../job-user-assign-dialog.module');
// the `importedModuleFile` has all the imports of the file
// and since one of them is `JobUserAssignDialogModule`
// we can use it to invoke previously defined `getComponent()` method
return this.matDialog.open(
importedModuleFile.JobUserAssignDialogModule.getComponent(),
{data},
);
}
}
scructureは次のようになります.
![](https://s1.md5.ltd/image/cdb31bbb6433ac1d65e12710c438b5f8.png)
各ダイアログ:
Don't forget to remove Dialog Module imports from your
AppModule
github repoはstackblitzと同様に以下のようになります.
ハンバーグ / 角度における遅延負荷ダイアログ
遅延負荷角ダイアログのショーケース
結論
最後の5分の間に、なぜすべてのダイアログを一度にロードすることが最適ではないことを学んだ.ダイアログがバンドルされている問題を発見したmain.js
ファイル.また、クラスを値として使用し、それを型として使用することの違いもわかりました.最後に、すべてのダイアログのソリューションを非同期でモジュールクラスを読み込み、コンポーネントクラスのリファレンスを取得するためのプロキシとして使用することで、実装を行います.
私は、あなたが私がそれが可能であるとわかったとき、私がそうであったのと同じくらい感銘を受けることを望みます:)
次の記事では角度について書きます.おそらく.
周りを見ろ.
Reference
この問題について(アングル・アーキテクチャ), 我々は、より多くの情報をここで見つけました
https://dev.to/humberd/angular-architecture-lazy-loaded-dialogs-59di
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
Reference
この問題について(アングル・アーキテクチャ), 我々は、より多くの情報をここで見つけました https://dev.to/humberd/angular-architecture-lazy-loaded-dialogs-59diテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol