wake-up-neo.net

Implementieren einer Plugin-Architektur / eines Plugin-Systems / eines Plugin-Frameworks in Angular 2, 4, 5, 6

Update 24.05.2008: Wir haben jetzt +3 Versionen von Angular von meinem ursprünglichen Beitrag und ziehen immer noch nicht an. ' Es gibt keine endgültige funktionierende Lösung. Lars Meijdam (@LarsMeijdam) hat einen interessanten Ansatz gefunden, der auf jeden Fall einen Blick wert ist. (Aufgrund proprietärer Probleme musste er das GitHub-Repository vorübergehend entfernen, in dem er sein Sample ursprünglich bereitgestellt hatte Sie können ihm jedoch direkt eine Nachricht senden, wenn Sie eine Kopie wünschen. Weitere Informationen finden Sie in den Kommentaren unten.)

Die jüngsten architektonischen Änderungen in Angular 6 bringen uns einer Lösung näher. Zusätzlich Angular= Elements ( https://angular.io/guide/elements ) bietet einige Komponentenfunktionen - obwohl nicht ganz das, was ich ursprünglich in diesem Beitrag beschrieben habe.

Wenn jemand aus dem erstaunlichen Angular) -Team auf dies stößt, beachten Sie bitte, dass es anscheinend viele andere Leute gibt, die ebenfalls sehr an dieser Funktionalität interessiert sind. Es könnte sich lohnen, über den Rückstand nachzudenken .


Ich möchte ein Plug-In-Framework in einer Anwendung Angular 2, Angular 4, Angular 5 Oder Angular 6 Implementieren.

(Mein spezieller Anwendungsfall für die Entwicklung dieses steckbaren Frameworks ist die Entwicklung eines Miniatur-Content-Management-Systems. Aus einer Reihe von Gründen, die hier nicht unbedingt ausgeführt werden müssen, ist Angular 2/4/5/6 Für die meisten Anforderungen nahezu perfekt geeignet System.)

Unter steckbarem Framework (oder Plug-in-Architektur) verstehe ich insbesondere ein System, mit dem Entwickler von Drittanbietern die Funktionalität einer primären Anwendung durch die Verwendung steckbarer Komponenten erstellen oder erweitern können ohne direkten Zugriff auf oder Kenntnis der Quellcode der Primäranwendung oder innere Funktionsweise.

(Diese Formulierung über " ohne direkten Zugriff auf oder Kenntnis des Quellcodes oder der inneren Funktionsweise der Anwendung" ist ein Kernziel.)

Beispiele für steckbare Frameworks sind gängige Content-Management-Systeme wie WordPress oder Drupal.

Die ideale Situation (wie bei Drupal) wäre, einfach diese steckbaren Komponenten (oder Plug-Ins) in einem Ordner zu platzieren, die Anwendung automatisch erkennen oder erkennen zu lassen und sie einfach auf magische Weise "arbeiten" zu lassen. Wenn dies in einer Art Hot-Plug-Modus erfolgt, dh während die App ausgeführt wird, ist dies optimal.

Ich versuche gerade, Antworten ( mit Ihrer Hilfe) auf die folgenden fünf Fragen zu finden.

  1. Praktikabilität: Ist ein Plugin-Framework für eine Angular 2/4/5/6 - Anwendung überhaupt praktisch? (Bisher habe ich keine praktische Möglichkeit gefunden, mit Angular2/4/5/6 Ein wirklich steckbares Framework zu erstellen.)
  2. Erwartete Herausforderungen: Welche Herausforderungen können bei der Implementierung eines Plugin-Frameworks für eine Angular 2/4/5/6 - Anwendung auftreten?
  3. Implementierungsstrategien: Welche spezifischen Techniken oder Strategien können zur Implementierung eines Plugin-Frameworks für eine Angular 2/4/5/6 - Anwendung eingesetzt werden?
  4. Best Practices: Was sind die Best Practices für die Implementierung eines Pluginsystems für eine Angular 2/4/5/6 - Anwendung?
  5. Alternative Technologien: If Ein Plugin-Framework ist not praktisch in einem Angular 2/4/5/6 - Anwendung, welche relativ äquivalenten Technologien (z. B. React) könnten für eine moderne hochreaktive Webanwendung geeignet sein?

Im Allgemeinen ist die Verwendung von Angular 2/4/5/6 Aus folgenden Gründen sehr wünschenswert:

  • es ist natürlich extrem schnell - blitzschnell.
  • es verbraucht sehr wenig Bandbreite (nach dem ersten Laden)
  • es hat einen relativ kleinen Footprint (nach AOT und tree shaking) - und dieser Footprint schrumpft weiter
  • es ist hoch funktional und das Angular Team und die Community wachsen weiterhin rasant an seinem Ökosystem
  • es funktioniert gut mit vielen der besten und neuesten Webtechnologien wie TypeScript und Observables
  • Angular 5 unterstützt jetzt Servicemitarbeiter ( https://medium.com/@webmaxru/a-new-angular-service-worker-creating-automatic-progressive-web-apps-part-1-theory-37d7d7647cc7 )
  • da es von Google unterstützt wird, wird es wahrscheinlich auch in Zukunft unterstützt und verbessert

Ich würde sehr gerne Angular 2/4/5/6 Für mein aktuelles Projekt verwenden. Wenn ich Angular 2/4/5/6 Verwenden kann, verwende ich auch Angular-CLI Und wahrscheinlich Angular Universal (Für das serverseitige Rendern).

Hier sind meine Gedanken zu den obigen Fragen. Bitte überprüfen Sie und geben Sie Ihr Feedback und Aufklärung.

  • Angular 2/4/5/6 Apps verbrauchen Pakete - dies ist jedoch nicht unbedingt das Gleiche wie das Zulassen von Plugins innerhalb einer Anwendung. Ein Plugin in anderen Systemen (z. B. Drupal) kann im Wesentlichen durch Ablegen des Plugin-Ordners in einem allgemeinen Modulverzeichnis hinzugefügt werden, in dem es vom System automatisch "abgeholt" wird. In Angular 2/4/5/6 Wird ein Paket (wie ein Plugin sein könnte) normalerweise über npm installiert, zu package.json Hinzugefügt und dann manuell in die App importiert - wie in app.module. Dies ist viel komplizierter als die Methode Drupal, mit der ein Ordner gelöscht wird und das System das Paket automatisch erkennt. Je komplizierter die Installation eines Plugins ist, desto unwahrscheinlicher ist die Verwendung. Es wäre viel besser, wenn es eine Möglichkeit gäbe, Angular 2/4/5/6 Automatisch zu erkennen und Plugins installieren. Ich bin sehr daran interessiert, eine Methode zu finden, die es Nicht-Entwicklern ermöglicht, die Angular 2/4/5/6 - Anwendung zu installieren und alle ausgewählten Plugins zu installieren, ohne die gesamte Architektur der Anwendung verstehen zu müssen.

  • Im Allgemeinen ist einer der Vorteile der Bereitstellung einer steckbaren Architektur, dass es für Entwickler von Drittanbietern sehr einfach ist, die Funktionalität des Systems zu erweitern. Offensichtlich sind diese Entwickler nicht mit allen Feinheiten des Codes für die Anwendung vertraut, in die sie sich einfügen. Sobald die Plugins entwickelt sind, können andere, noch weniger technische Benutzer einfach die Anwendung und alle ausgewählten Plugins installieren. Angular 2/4/5/6 Ist jedoch relativ kompliziert und weist eine sehr lange Lernkurve auf. Um die Sache noch weiter zu komplizieren, verwenden die meisten Produktionsanwendungen Angular 2/4/5/6 Auch Angular-CLI, Angular Universal Und WebPack. Jemand, der ein Plugin implementiert, muss wahrscheinlich zumindest einige Grundkenntnisse darüber haben, wie all diese zusammenpassen - zusammen mit soliden Kenntnissen von TypeScript und einer angemessenen Vertrautheit mit NodeJS. Sind die Wissensanforderungen so hoch, dass kein Dritter jemals ein Plugin entwickeln möchte?

  • Die meisten Plugins haben wahrscheinlich eine serverseitige Komponente (z. B. zum Speichern/Abrufen von Plugin-bezogenen Daten) sowie eine clientseitige Ausgabe. Angular 2/4/5 Hält Entwickler ausdrücklich (und nachdrücklich) davon ab, zur Laufzeit eigene Vorlagen einzufügen, da dies ein ernstes Sicherheitsrisiko darstellt. Um viele Arten von Ausgaben verarbeiten zu können, die in einem Plug-In enthalten sein können (z. B. die Anzeige eines Diagramms), ist es wahrscheinlich erforderlich, Benutzern das Erstellen von Inhalten zu ermöglichen, die in einer anderen Form in den Antwortstrom eingefügt werden. Ich frage mich, wie es möglich sein könnte, dieses Bedürfnis zu befriedigen, ohne die Sicherheitsmechanismen von Angular 2/4/5/6 Im übertragenen Sinne zu vernichten.

  • Die meisten Produktionsanwendungen Angular 2/4/5/6 Werden mit der Kompilierung Ahead of Time (AOT) vorkompiliert. (Wahrscheinlich sollte das alles sein.) Ich bin mir nicht sicher, wie Plugins zu vorkompilierten Anwendungen hinzugefügt (oder in diese integriert) werden können. Das beste Szenario wäre, die Plugins getrennt von der Hauptanwendung zu kompilieren. Ich bin mir jedoch nicht sicher, wie ich das machen soll. Ein Fallback könnte darin bestehen, die gesamte Anwendung mit allen enthaltenen Plugins neu zu kompilieren. Dies erschwert jedoch die Arbeit für einen Administrator, der die Anwendung (auf seinem eigenen Server) zusammen mit ausgewählten Plugins installieren möchte.

  • In einer Angular 2/4/5/6 - Anwendung, insbesondere einer vorkompilierten, kann ein einzelner fehlerhafter oder widersprüchlicher Code die gesamte Anwendung beschädigen. Angular 2/4/5/6 - Anwendungen sind nicht immer am einfachsten zu debuggen. Die Verwendung von Plugins, die sich schlecht verhalten, kann zu sehr unangenehmen Erfahrungen führen. Mir ist derzeit kein Mechanismus bekannt, mit dem Plugins, die sich schlecht verhalten, ordnungsgemäß gehandhabt werden können.

116
Anthony Gatlin

Ich habe ein Repository auf Github mit einer Lösung erstellt, die helfen könnte. Es werden Angular 6 Bibliotheken und 1 Basisanwendung verwendet, die die UMD-Bibliotheken im Bundle träge laden; https://github.com/lmeijdam/angular-umd-dynamic-example =

Wenn Sie Vorschläge haben, können Sie diese gerne hinzufügen!

14
Lars Meijdam

Ich habe gerade ein neues Kapitel für mein Buch " Developing with Angular " veröffentlicht, das das Thema Plugins in Angular 2+) behandelt und für die Leute von großem Interesse sein sollte das versuchen, externe Plugins zu erstellen.

Wichtige Punkte:

  • Plugins
  • Erstellen von Komponenten basierend auf Zeichenfolgennamen
  • Konfiguration von externen Quellen laden
  • Dynamisch wechselnde Anwendungsrouten
  • Externe Plugins
  • Plugin-Bibliotheken erstellen
  • Laden von Plugins in die Anwendung
  • Dynamische Routen mit Plugin-Inhalten

Das Buch ist kostenlos erhältlich und hat das Modell "Bezahlen, was Sie wollen". Gerne können Sie sich eine Kopie holen und hoffen, dass dies hilft.

10
Denys Vuika

Beispielanwendung mit einem funktionierenden Pluginsystem (Danke an Gijs für die Gründung des Github-Repos!) https://github.com/PacktPublishing/Mastering-Angular-2-Components/tree/master/angular-2-components- Kapitel-1 basierend auf dem eBook Mastering Angular 2 Components

  • plugin-Architektur zur Erweiterung der wichtigsten App-Komponenten
  • datei-Plugin-System (zum einfachen Hinzufügen von Plugin-Verzeichnissen/-Dateien, ohne dass Kernkonfigurationsdateien bearbeitet werden müssen oder die Anwendung neu kompiliert werden muss!)
  • plugins laden und dynamisch nutzen
  • erstellen eines rudimentären Plugin-Managers, um Plugins im laufenden Betrieb zu aktivieren/deaktivieren

Prost, Niklas

6
Niklas Teich

Was Sie suchen, ist faul Modulladen. Hier ist ein Beispiel dafür: 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;
    }
  }
}

Am besten ... Tom

5
Tom I

???? ️ Github Demo Angular-Plugin-Architektur

Vielleicht kann Ivy etwas ändern, aber zur Zeit verwende ich die Lösung, die Angular CLI Custom Builder verwendet und die folgenden Anforderungen erfüllt:

  • AOT
  • vermeiden Sie doppelten Code (Pakete wie @ angle/core {common, forms, router}, rxjs, tslib)
  • verwenden Sie die gemeinsam genutzte Bibliothek in allen Plugins, versenden Sie jedoch KEINE von dieser gemeinsam genutzten Bibliothek generierten Fabriken in jedem Plugin, sondern verwenden Sie den Bibliothekscode und die Fabriken erneut
  • das gleiche Maß an Optimierung, das Angular CLI uns gibt
  • für den Import der externen Module müssen wir nur eines wissen: den Pfad der Bundle-Datei
  • unser Code sollte das Modul erkennen und das Plugin in die Seite einfügen
  • unterstützung für serverseitiges Rendering
  • modul nur bei Bedarf laden

Die Verwendung ist einfach wie folgt:

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

Mehr dazu in meinem Artikel:

5
yurzui

Ich habe versucht, eine Plugin-Architektur mit ABP, Angular und ASP.NET Core: https://github.com/chanjunweimy/abp_plugin_with_ui zu implementieren

Grundsätzlich habe ich angular plugins mit verschiedenen angular application entwickelt und diese dann dynamisch zusammengefügt.

Weitere Informationen darüber, wie ich es erreiche:

Ich habe 2 Angular-Cli-Anwendung, 1 ist die wichtigste angular Cli-Anwendung, und eine andere ist das Plugin angular Cli-Anwendung. Das Problem, dem wir in Angular gegenüberstehen -cli Plugin-Architektur Ansatz ist, wie wir sie integrieren.

Im Moment habe ich ng-build auf beiden Anwendungen ausgeführt und sie in einen "wwwroot" -Ordner verschoben, der dann auf einem ASP.NET Core 2.0-Server gehostet wurde. Ein einfacheres Repository, das diese Idee zeigt, ist Angular Multiple App: https://github.com/chanjunweimy/angular-multiple-app

abp_plugin_with_ui ist ein Repository, das an der Entwicklung eines Plugins arbeitet, das sowohl das Backend als auch Angular cli enthält. Für das Backend habe ich das aspnetboilerplate-Framework verwendet, für das das Frontend mehrere Angular-Cli verwendet Anwendung.

Um die Hauptanwendung in die Plugin-Anwendung zu integrieren, müssen Sie auf beiden Anwendungen "ng-build" ausführen (beachten Sie, dass Sie auch in href der Plugin-Anwendung wechseln müssen). Anschließend verschieben Sie den erstellten Inhalt des Plugins angular cli-Anwendung zum Hauptanwendungsordner "wwwroot". Nachdem dies erreicht ist, können wir "dotnet run" ausführen, um die ASP.NET Core 2.0-Webanwendung zum Hosten der statischen Dateien bereitzustellen generiert durch "ng build".

Hoffentlich hilft es. Kommentare sind willkommen! ^^

2
Junwei Chan

ich bin derzeit in der gleichen Mission wie Sie und versuche, eine Pluggable/Themable-Version von Angular zu erstellen, und es ist kein triviales Problem.

Eigentlich habe ich ziemlich gute Lösungen gefunden, indem ich das Buch Developing with Angular vom Genius Denys Vuyika gelesen habe, er erklärt tatsächlich auf dem Buch eine ziemlich gute Lösung, er spricht Informationen zu externen Plug-ins finden Sie auf Seite 356 des Handbuchs. Verwenden Sie Rollup.js , um die Lösung zu erzielen, und laden Sie dann dynamisch externe Plug-ins, die zuvor außerhalb Ihrer Anwendung erstellt wurden.

Es gibt auch zwei andere Bibliotheken/Projekte, die Ihnen helfen, dieses Ergebnis zu erzielen ng-packagr und Nx-Erweiterungen für Agnular (von Nrwl) Wir sind dabei, die zu implementieren Letzteres, und ich würde sagen, dass es nicht so flüssig ist, wie wir es erwartet hatten. angular war einfach nicht dafür gebaut, also müssen wir einen Teil des Kerns von Angular und NX umgehen ppls sind eine der besten auf.

Wir stehen erst am Anfang unseres Open Source-Projekts und verwenden Django + Mongo + Angular. (Wir nennen WebDjangular und einer unserer möglichen Ansätze für diese Antwort ist Django muss bei jeder Installation und Aktivierung eines neuen Plugins oder Themes einige JSON-Konfigurationsdateien schreiben und die Anwendung erstellen.

Was wir bereits erreicht haben, ist, dass wir aus der Datenbank Tags für die Komponenten wie im Plugin verwenden können und die Komponente auf dem Bildschirm gedruckt wird! Das Projekt befindet sich wieder in einem sehr frühen Stadium. Wir bauen unsere Architektur ein wenig auf Wordpress auf und müssen noch viele weitere Tests durchführen, um unseren Traum zu verwirklichen: D

Ich hoffe, das Buch kann Ihnen helfen, und wenn Sie Rollup.js verwenden, wissen Sie, dass Sie in der Lage sind, dieses nicht triviale Problem zu lösen.

2

Ich habe in bootstrap time einen Hack zum Laden gemacht und andere Module kompiliert, aber ich habe das Problem der zyklischen Abhängigkeiten nicht gelöst

 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));

fügen Sie dann in AppModule Folgendes hinzu:

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

Dies kann "manuell" erfolgen. Da Webpack nichts über externe (Plug-In-) Module weiß, kann er sie nicht in Bundles aufnehmen. Also habe ich mir den Code angesehen, der durch das Webpack generiert wurde und ich habe diese Code-Pies in main.bundle.js gefunden:

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

Untersuchen wir, was dieses Array enthält:

  1. "./ dashboard/dashboard.module" - Dies ist die Routing-URL des Moduls, das wir verzögern möchten, zum Beispiel: {Pfad: 'dashboard', loadChildren : './dashboard/dashboard.module#DashboardModule'}
  2. "../../../../../ src/app/dashboard/dashboard.module.ts" - Dies ist der Einstiegspunkt (Konstruktor) von
  3. "dashboard.module" - tatsächlicher Dateiname ohne chunk.js (Beispiel: dashboard.module.chunk.js )

Wenn Sie also theoretisch der Karteneigenschaft einen Eintrag hinzufügen, konfigurieren Sie Ihr Routing und folgen Sie dem Muster. Dann können Sie ein Plug-In-System verwenden. Die Herausforderung besteht nun darin, Einträge zu dieser Karteneigenschaft hinzuzufügen oder daraus zu entfernen. Offensichtlich kann es nicht mit angular Code gemacht werden, es sollte für ein externes Tool gemacht werden.

2
Niki Uzun

Ein wenig abseits des Themas, aber die Bibliotheken der UI-Komponenten könnten für einige Leser von Interesse sein, die nach Plugins suchen:
https://medium.com/@nikolasleblanc/building-an-angular-4-component-library-with-the-angular-cli-and-ng-packagr-53b2ade0701e

NativeScript verfügt über integrierte UI-Plugins:
https://docs.nativescript.org/plugins/building-plugins
Diese Plugins benötigen einen Angular Wrapper:
https://docs.nativescript.org/plugins/angular-plugin

2
RaSor

Ich habe nach einem Plugin-System in angular 2/4 gesucht, um eine RAD) - Umgebung für eine Unternehmensanwendung bei der Arbeit zu entwickeln. Nach einigen Recherchen habe ich mich dazu entschlossen Implementieren einer Sammlung von in einer Datenbank gespeicherten (möglicherweise im Dateisystem befindlichen) Pseudo-Angular-Komponenten.

Die in der Datenbank Datenbank gespeicherten Komponenten basieren auf ng-dynamic und die Implementierung der Hauptkomponente ist ähnlich wie folgt:

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();
                }

            });

        });

    }

Der externe Javascript-Code ähnelt angular Komponenten:

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'; 

};

Und die Vorlagen der Komponenten sind wie angular Vorlagen:

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

Und könnte auch verschachtelt sein:

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

Obwohl es nicht perfekt ist, haben die Entwickler der benutzerdefinierten Komponenten ein ähnliches Framework wie in angle2/4.

2
zarpilla

Ich fand einen guten Artikel von Paul Ionescu über das Erstellen einer erweiterbaren Plugin-Anwendung in Angular.

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

Er verweist auch auf eine Beispielanwendung bei github: https://github.com/ionepaul/angular-plugin-architecture

0
Marvin Caspar