web-dev-qa-db-ja.com

Angular 2、4、5、6にプラグインアーキテクチャ/プラグインシステム/プラガブルフレームワークを実装する

2018年5月24日更新:元の投稿からAngularの+3バージョンになりましたが、まだありません最終的な実行可能なソリューション。 Lars Meijdam(@LarsMeijdam)は、確かに一見の価値がある興味深いアプローチを思いつきました。 (所有権の問題のため、彼はサンプルを最初に投稿したGitHubリポジトリを一時的に削除する必要がありました。しかし、コピーが必要な場合は直接彼にメッセージを送ることができます。詳細については以下のコメントを参照してください。)

Angular 6の最近のアーキテクチャの変更により、ソリューションに近づきました。さらに、Angular Elements( https://angular.io/guide/elements )はいくつかのコンポーネント機能を提供しますが、この投稿で最初に説明したものとは異なります。

驚くべきAngularチームの誰かがこれに出くわした場合、この機能に非常に興味を持っている他の多くの人々があるように注意してください。バックログを検討する価値があるかもしれません。


プラグイン可能な(プラグイン)フレームワークをAngular 2Angular 4Angular 5、またはAngular 6アプリケーションに実装したいと思います。

(このプラグ可能なフレームワークを開発するための私の特定のユースケースは、ミニチュアコンテンツ管理システムを開発する必要があるということです。ここでは必ずしも詳しく説明しませんが、いくつかの理由により、Angular 2/4/5/6はそのシステムのほとんどのニーズにほぼ適合しています。)

プラガブルフレームワーク(またはプラグインアーキテクチャ)とは、具体的には、サードパーティの開発者がプラガブルコンポーネントを使用してプライマリアプリケーションの機能を作成または拡張できるシステムを意味します直接アクセスしたり、プライマリアプリケーションのソースコードまたは内部動作

(「アプリケーションのソースコードや内部の仕組みに直接アクセスしたり、知識がない」という言い回しは、中核的な目的です。)

プラグ可能なフレームワークの例には、WordPressDrupalなどの一般的なコンテンツ管理システムが含まれます。

理想的な状況(Drupalの場合と同様)は、これらのプラグ可能なコンポーネント(またはプラグイン)をフォルダーに簡単に配置し、アプリケーションに自動検出または検出させ、魔法のように「機能させる」ことです。これが何らかのホットプラグ可能な方法で発生するのは、アプリの実行中に最適であるという意味です。

現在、次の5つの質問に対する回答(with your help)を決定しようとしています。

  1. 実用性:Angular 2/4/5/6アプリケーションのプラグインフレームワークはさらに実用的ですか? (今まで、Angular2/4/5/6を使用して真にプラグ可能なフレームワークを作成する実用的な方法は見つかりませんでした。)
  2. 期待される課題:Angular 2/4/5/6アプリケーションにプラグインフレームワークを実装する際に遭遇する可能性のある課題は何ですか?
  3. 実装戦略:Angular 2/4/5/6アプリケーション用のプラグインフレームワークを実装するためにどのような特定の手法または戦略を採用できますか?
  4. ベストプラクティス:Angular 2/4/5/6アプリケーションにプラグインシステムを実装するためのベストプラクティスは何ですか?
  5. 代替技術:IfプラグインフレームワークはnotAngular 2/4/5/6アプリケーションで実用的、何- 比較的同等テクノロジー(たとえばReact)は、現代の非常に反応性の高いWebアプリケーション

一般的に、Angular 2/4/5/6の使用は非常に望ましい:

  • 当然、非常に高速です。
  • 消費する帯域幅が非常に少ない(初期ロード後)
  • AOTおよびtree shakingの後)フットプリントが比較的小さく、そのフットプリントは縮小し続けます
  • 機能性が高く、Angularチームとコミュニティはそのエコシステムの急速な成長を続けています
  • TypeScriptObservablesなどの最新のWebテクノロジーの多くでうまく機能します
  • Angular 5はサービスワーカーをサポートするようになりました( https://medium.com/@webmaxru/a-new-angular-service-worker-creating-automatic-progressive-web-apps-part-1-theory-37d7d7647cc7
  • Googleによって支援されているため、将来的にもサポートおよび拡張される可能性が高い

現在のプロジェクトにAngular 2/4/5/6を使用したいと思います。 Angular 2/4/5/6を使用できる場合は、Angular-CLIおよびおそらくAngular Universalも使用します(サーバー側レンダリング用)。

上記の質問に関するこれまでの私の考えを以下に示します。 フィードバックと啓発を確認し、提供してください。

  • Angular 2/4/5/6アプリはパッケージを消費しますが、これは必ずしもアプリケーション内でプラグインを許可することと同じではありません。他のシステムのプラグイン(Drupalなど)は、プラグインフォルダーをシステムによって自動的に「ピックアップ」される共通モジュールディレクトリにドロップすることで、基本的に追加できます。 Angular 2/4/5/6では、(プラグインとして)パッケージは通常npmを介してインストールされ、package.jsonに追加され、app.moduleのようにアプリに手動でインポートされます。これは、フォルダーをドロップし、システムにパッケージを自動的に検出させるDrupalメソッドよりもはるかに複雑です。 プラグインのインストールが複雑になるほど、人々がプラグインを使用する可能性は低くなります。Angular 2/4/5/6がプラグインを自動的に検出してインストールする方法があれば、はるかに良いでしょう。開発者以外がAngular 2/4/5/6アプリケーションをインストールし、アプリケーションのアーキテクチャをすべて理解しなくても選択したプラグインをインストールできる方法を見つけることに非常に興味があります。

  • 一般に、プラグ可能なアーキテクチャを提供する利点の1つは、サードパーティの開発者がシステムの機能を拡張することが非常に簡単であることです。明らかに、これらの開発者は、プラグインするアプリケーションのコードの複雑さのすべてに精通しているわけではありません。プラグインが開発されると、他の技術的でないユーザーでも、アプリケーションと選択したプラグインをインストールするだけで済みます。ただし、Angular 2/4/5/6は比較的複雑で、学習曲線が非常に長くなります。さらに複雑なことに、ほとんどの実動Angular 2/4/5/6アプリケーションは、Angular-CLIAngular Universal、およびWebPackも利用します。プラグインを実装している人は、TypeScriptの強力な実用的な知識とNodeJSの合理的な知識に加えて、これらのすべてがどのように適合するかについて少なくともいくつかの基本的な知識を持っている必要があります。サードパーティがプラグインを開発することを望まないほど知識の要件は極端ですか?

  • ほとんどのプラグインには、クライアント側の出力だけでなく、サーバー側のコンポーネント(プラグイン関連データの保存/取得など)が含まれている可能性があります。 Angular 2/4/5は、開発者が実行時に独自のテンプレートをインジェクトすることを特に(そして強く)抑制します。これは深刻なセキュリティリスクをもたらすためです。プラグインが対応できる多くの種類の出力(グラフの表示など)を処理するには、ユーザーが応答ストリームに注入されるコンテンツを作成できるようにする必要があるようです。 Angular 2/4/5/6のセキュリティメカニズムを比ur的に細断することなく、このニーズにどのように対応できるのかと思います。

  • ほとんどの実動Angular 2/4/5/6アプリケーションは、Ahead of TimeAOT)コンパイルを使用してプリコンパイルされます。 (おそらくすべてのはずです。)プリコンパイルされたアプリケーションにプラグインを追加(または統合)する方法がわかりません。最良のシナリオは、メインアプリケーションとは別にプラグインをコンパイルすることです。しかし、私はこの仕事をする方法がわかりません。フォールバックは、含まれているプラ​​グインを使用してアプリケーション全体を再コンパイルすることですが、選択したプラグインとともにアプリケーションを(自分のサーバーに)インストールするだけの管理ユーザーにとっては少し複雑になります。

  • Angular 2/4/5/6アプリケーション、特にプリコンパイルされたアプリケーションでは、1つの誤ったコードまたは競合するコードがアプリケーション全体を破壊する可能性があります。 Angular 2/4/5/6アプリケーションは常にデバッグするのが最も簡単ではありません。不適切なプラグインを適用すると、非常に不愉快な経験をする可能性があります。私は現在、不適切なプラグインを適切に処理するメカニズムを知りません。

112
Anthony Gatlin

役立つかもしれない解決策でgithubにリポジトリを作成しました。 Angular 6つのライブラリと1つのベースアプリケーションを使用して、UMDバンドルライブラリを遅延的にロードします。 https://github.com/lmeijdam/angular-umd-dynamic-example

何か提案があれば、気軽に追加してください!

14
Lars Meijdam

私は私の本の新しい章を公開しました " Developing with Angular "これはAngular 2+のプラグインのトピックに対応しており、外部プラグインを構築します。

キーポイント:

  • プラグイン
  • 文字列名に基づいたコンポーネントの構築
  • 外部ソースからの設定の読み込み
  • 動的に変化するアプリケーションルート
  • 外部プラグイン
  • プラグインライブラリの作成
  • プラグインをアプリケーションにロードする
  • プラグインコンテンツを使用した動的ルート

本は無料で入手でき、「欲しいものを支払う」モデルがあります。コピーを手に入れて、それが役立つことを願ってください。

11
Denys Vuika

動作するプラグインシステムを使用したサンプルアプリケーション(githubリポジトリを作成してくれたGijsに感謝!) https://github.com/PacktPublishing/Mastering-Angular-2-Components/tree/master/angular-2-components- chapter-1 eBookに基づく Mastering Angular 2 Components

  • コアアプリコンポーネントを拡張するプラグインアーキテクチャ
  • ファイルプラグインシステム(コアの構成ファイルを編集したり、アプリケーションを再コンパイルしたりすることなく、単にプラグインディレクトリ/ファイルを追加するだけです!)
  • プラグインをロードして動的に使用する
  • オンザフライでプラグインを有効化/無効化するための初歩的なプラグインマネージャーの構築

乾杯、ニクラス

6
Niklas Teich

探しているのは、遅延モジュールの読み込みです。以下に例を示します。 http://plnkr.co/edit/FDaiDvklexT68BTaNqvE?p=preview

import {Component} from '@angular/core';
import {Router} from '@angular/router';

@Component({
  selector: 'my-app',
  template: `
    <a [routerLink]="['/']">Home</a> | 
    <a [routerLink]="['/app/home']">App Home</a> |
    <a [routerLink]="['/app/lazy']">App Lazy</a>

    <hr>
    <button (click)="addRoutes()">Add Routes</button>

    <hr>
    <router-outlet></router-outlet>
  `
})
export class App {
  loaded: boolean = false;
  constructor(private router: Router) {}

  addRoutes() {
    let routerConfig = this.router.config;

    if (!this.loaded) {
      routerConfig[1].children.Push({
        path: `lazy`,
        loadChildren: 'app/lazy.module#LazyModule'
      });

      this.router.resetConfig(routerConfig);
      this.loaded = true;
    }
  }
}

ベスト...トム

5
Tom I

???️Githubデモ angular-plugin-architecture

Ivyは何かを変更できるかもしれませんが、当面はAngular CLIカスタムビルダーを使用し、次の要件を満たすソリューションを使用します。

  • AOT
  • コードの重複を避ける(@ angular/core {common、forms、router}、rxjs、tslibなどのパッケージ)
  • すべてのプラグインで共有ライブラリを使用しますが、各プラグインでその共有ライブラリから生成されたファクトリを出荷せず、ライブラリコードとファクトリを再利用します
  • Angular CLIが提供するのと同じレベルの最適化
  • 外部モジュールをインポートするために必要なことは、バンドルファイルパスだけです。
  • コードはモジュールを認識し、プラグインをページに配置する必要があります
  • サーバー側レンダリングをサポート
  • 必要な場合にのみモジュールをロード

使い方は次のように簡単です。

ng build --project plugins --prod --modulePath=./plugin1/plugin1.module#Plugin1Module 
         --pluginName=plugin1 --sharedLibs=shared --outputPath=./src/assets/plugins

これについては私の記事で詳しく説明します。

4
yurzui

ABP、AngularおよびASP.NET Coreを使用してプラグインアーキテクチャを実装しようとしました: https://github.com/chanjunweimy/abp_plugin_with_ui

基本的に、さまざまなangularアプリケーションを使用してangularプラグインを開発し、それらを動的に追加します。

達成方法の詳細:

2つのangle-cliアプリケーションがあり、1つはメインangular cliアプリケーション、もう1つはプラグインangular cliアプリケーションです。 Angular-cliプラグインアーキテクチャアプローチで直面している問題は、それらを統合する方法です。

今、私がやったことは、両方のアプリケーションでng-buildを実行し、それらを「wwwroot」フォルダーに入れて、ASP.NETコア2.0サーバーでホストしたことです。このアイデアを示す簡単なリポジトリは、Angular Multiple App: https://github.com/chanjunweimy/angular-multiple-app

abp_plugin_with_uiは、バックエンドとAngular cliの両方を含むプラグインの開発に取り組むリポジトリです。バックエンドには、aspnetboilerplateフレームワークを使用しました。これは、フロントエンドが複数のangle-cliアプリケーションを使用して開発されたものです。

メインアプリケーションをプラグインアプリケーションと統合するには、両方のアプリケーションで「ng-build」を実行する必要があり(プラグインアプリケーションのhrefにも変更する必要があることに注意してください)、プラグインのビルドされたコンテンツを移動しますangular cliアプリケーション、メインアプリケーションの「wwwroot」フォルダー。これをすべて達成した後、「ng build」によって生成された静的ファイルをホストするASP.NET Core 2.0 Webアプリケーションを提供する「dotnet run」を実行できます。

うまくいけばそれが役立つ。コメントは大歓迎です! ^^

2
Junwei Chan

私は現在、あなたと同じ探求に取り組んでおり、Angularのプラグイン可能/ Themableバージョンを作成しようとしていますが、些細な問題ではありません。

私は実際に本を読んでかなり良い解決策を見つけました Developing with Angular by the Genius Denys Vuyika 、彼は実際に本でかなり良い解決策を説明し、彼は外部プラグインについて話しています本のページ356でソリューションを実現するために Rollup.js を使用し、その後、アプリケーションの外部で以前にビルドされた外部プラグインを動的にロードするために処理します。

この結果を達成するのに役立つ2つのライブラリ/プロジェクトもあります ng-packagr および NrwlからのAgnularのNx拡張 angularはそのために構築されたものではなく単純だったので、Angularがどのように機能するかについてコアの一部を回避する必要があり、NX pplsはそれ。

私たちはオープンソースプロジェクトの始まりに過ぎず、Django + Mongo + Angularを使用しています( WebDjangular を呼び出しており、この答えへの可能なアプローチの1つは、Djangoは、新しいプラグインまたはテーマがインストールおよびアクティブ化されるたびに、JSON構成ファイルをいくつか作成し、アプリケーションをビルドする必要があります。

すでに達成したことは、データベースから、プラグインなどのコンポーネントにタグを使用することができ、コンポーネントが画面に印刷されることです!繰り返しになりますが、プロジェクトは非常に初期の段階にあり、Wordpressに少し基づいてアーキテクチャを構築しています。夢を実現するために、さらに多くのテストを行う必要があります:D

この本があなたのお役に立てば幸いです。Rollup.jsを使えば、この些細な問題を解くことができると思います。

2

bootstrapの時間で他のモジュールをロードおよびコンパイルするためのハックを作成しましたが、循環依存の問題を解決していません

 const moduleFile: any = require(`./${app}/${app}.module`),
                    module = moduleFile[Object.keys(moduleFile)[0]];

 route.children.Push({
     path: app,
     loadChildren: (): Promise<any> => module
 });
 promises.Push(this.compiler.compileModuleAndAllComponentsAsync(module));

次に、AppModuleでこれを追加します。

{
        provide: APP_INITIALIZER,
        useFactory: AppsLoaderFactory,
        deps: [AppsLoader],
        multi: true
},
2

「手動で」実行できます。 webpackは外部(プラグイン)モジュールについて何も知らないため、バンドルに含めることはできません。だから私がやったことは、webpackによって生成されたコードを見て、main.bundle.jsでこのコードのパイを見つけたことです:

var map = {
"./dashboard/dashboard.module": ["../../../../../src/app/dashboard/dashboard.module.ts","dashboard.module"]}; 

その配列に含まれるものを調べてみましょう。

  1. "./ dashboard/dashboard.module"-これは、遅延ロードしたいモジュールのルーティングURLです。例:{path: 'dashboard'、loadChildren : './dashboard/dashboard.module#DashboardModule'}
  2. "../../../../../ src/app/dashboard/dashboard.module.ts"-これは、エントリポイント(コンストラクター)から取得します
  3. "dashboard.module"-chunk.jsなしの実際のファイル名(例:dashboard.module.chunk.js

したがって、理論的には、マッププロパティにエントリを追加してルーティングを構成し、パターンに従うと、プラグインシステムを使用できます。ここでの課題は、そのマッププロパティにエントリを追加または削除する方法です。明らかにangularコードから実行することはできません。外部ツールに対して実行する必要があります。

2
Niki Uzun

少し外れたトピックですが、UIコンポーネントライブラリは、プラグインを検索する一部の読者にとって興味深いものです。
https://medium.com/@nikolasleblanc/building-an-angular-4-component-library-with-the-angular-cli-and-ng-packagr-53b2ade0701e

NativeScriptにはビルドインUIプラグインがあります:
https://docs.nativescript.org/plugins/building-plugins
これらのプラグインにはAngularラッパーが必要です。
https://docs.nativescript.org/plugins/angular-plugin

2
RaSor

私はangular 2/4のプラグインシステムも探していましたが、職場のエンタープライズアプリケーション用のRAD環境を開発していました。いくつかの調査の後、データベースに格納された(ただし、ファイルシステムに存在する可能性がある)疑似角型コンポーネントのコレクションを実装することにしました。

データベースデータベースに格納されるコンポーネントは ng-dynamic に基づいており、メインコンポーネントの実装はこれに似ています:

declare var ctx: any;

@Component({
    selector: 'my-template',
    template: `
<div>
    <div *dynamicComponent="template; context: { ctx: ctx };"></div>
</div>
  `,
    providers: [EmitterService],

})

export class MyTemplateComponent implements OnMount, AfterViewInit, OnChanges {


    // name
    private _name: string;
    get name(): string {
        return this._name;
    }
    @Input()
    set name(name: string) {
        this._name = name;        
        this.initTemplate();
    }

    template: string;
    ctx: any = null;

    private initTemplate() {

        this.templateSvc.getTemplate(this.name).subscribe(res => {
            // Load external JS with ctx implementation
            let promise1 = injectScript(res.pathJs);
            // Load external CCS
            let promise2 = injectScript(res.pathCss);

            Promise.all([promise1, promise2]).then(() => {

                // assign external component code
                this.ctx = ctx; //

                // sets the template
                this.template = res.template;

                this.injectServices();

                if (this.ctx && this.ctx.onInit) {
                    this.ctx.onInit();
                }

            });

        });

    }

外部JavaScriptコードはangularコンポーネントに似ています:

var ctx = {

// injected    
_httpService: {},
_emitterService: null,

// properies
model: {
    "title": "hello world!",
},


// events
onInit() {
    console.log('onInit');
},

onDestroy() {
    console.log('onDestroy');
},

onChanges(changes) {
    console.log('changes', changes);
},

customFunction1() {
    console.log('customFunction1');
},

childTemplateName: string = 'other-component'; 

};

そして、コンポーネントのテンプレートはangularテンプレートのようなものです:

<a (click)="customFunction1()">{{ ctx.model.title }}</a>
<input [(ngModel)]="ctx.model.title" type="text" />

また、ネストすることもできます。

<a (click)="customFunction1()">{{ ctx.model.title }}</a>
<my-template [name]="childTemplateName"></my-template>

完全ではありませんが、カスタムコンポーネントの開発者は、angular2/4よりも類似したフレームワークを使用しています。

2
zarpilla

Paul Ionescuから、Angularでプラグイン拡張可能アプリケーションを構築する方法についての良い記事を見つけました。

https://itnext.io/how-to-build-a-plugin-extensible-application-architecture-in-angular5-736890278f3f

彼はまた、githubのサンプルアプリケーションを参照しています。 https://github.com/ionepaul/angular-plugin-architecture

0
Marvin Caspar