145 votes

Mise en œuvre d'une architecture de plugins / d'un système de plugins / d'un cadre pluggable dans Angular 2, 4, 5, 6

Mise à jour du 24/5/2018 : Nous en sommes maintenant à +3 versions d'Angular depuis mon message initial et nous n'avons toujours pas de solution finale viable. Lars Meijdam (@LarsMeijdam) a proposé une approche intéressante qui vaut certainement le coup d'œil. (Pour des raisons de propriété, il a dû retirer temporairement le dépôt GitHub où il avait initialement publié son échantillon. Toutefois, vous pouvez lui envoyer un message directement si vous souhaitez en obtenir une copie. Veuillez consulter les commentaires ci-dessous pour plus d'informations).

Les récentes modifications de l'architecture d'Angular 6 nous rapprochent d'une solution. De plus, les éléments Angular ( https://angular.io/guide/elements ) fournit certaines fonctionnalités des composants - mais pas tout à fait ce que j'ai décrit à l'origine dans cet article.

Si quelqu'un de la formidable équipe Angular tombe sur ce sujet, veuillez noter que de nombreuses autres personnes semblent également très intéressées par cette fonctionnalité. Elle pourrait bien être prise en compte dans le backlog.


J'aimerais mettre en œuvre un cadre de travail enfichable (plug-in) dans un système de gestion de l'information. Angular 2 , Angular 4 , Angular 5 ou Angular 6 application.

(Mon cas d'utilisation spécifique pour le développement de ce cadre enfichable est que je dois développer un système de gestion de contenu miniature. Pour un certain nombre de raisons qui ne sont pas nécessairement développées ici, Angular 2/4/5/6 répond presque parfaitement à la plupart des besoins de ce système).

Par cadre enfichable (ou architecture enfichable), j'entends spécifiquement un système qui permet à des développeurs tiers de créer ou d'étendre la fonctionnalité d'une application principale grâce à l'utilisation de composants enfichables. sans avoir un accès direct au code source ou au fonctionnement interne de l'application primaire, ni en avoir connaissance .

(Cette phrase sur " sans avoir un accès direct ou une connaissance du code source ou du fonctionnement interne de l'application " est un objectif essentiel).

Parmi les exemples de cadres enfichables, citons les systèmes de gestion de contenu courants tels que WordPress o Drupal .

L'idéal (comme avec Drupal) serait de pouvoir simplement placer ces composants enfichables (ou plug-ins) dans un dossier, que l'application les détecte ou les découvre automatiquement et qu'ils fonctionnent comme par magie. L'idéal serait que cela puisse se faire à chaud, c'est-à-dire pendant l'exécution de l'application.

J'essaie actuellement de déterminer les réponses ( avec votre aide ) aux cinq questions suivantes.

  1. L'aspect pratique : est un cadre de plugin pour un Angular 2/4/5/6 même pratique ? (Jusqu'à présent, je n'ai pas trouvé de moyen pratique de créer un cadre réellement enfichable avec Angular2/4/5/6 .)
  2. Défis attendus : Quels défis pourrait-on rencontrer dans la mise en œuvre d'un cadre de plugin pour un Angular 2/4/5/6 application ?
  3. Stratégies de mise en œuvre : Quelles techniques ou stratégies spécifiques pourraient être employées pour mettre en œuvre un cadre de plugin pour une Angular 2/4/5/6 application ?
  4. Meilleures pratiques : Quelles sont les meilleures pratiques pour la mise en œuvre d'un système de plugin pour un Angular 2/4/5/6 application ?
  5. Technologies alternatives : Si un cadre pour les plugins est pas pratique dans un Angular 2/4/5/6 application, ce qui relativement équivalent les technologies (par exemple React ) pourrait convenir à un application Web moderne et hautement réactive ?

En général, l'utilisation de Angular 2/4/5/6 est très souhaitable car :

  • il est naturellement extrêmement rapide, à un rythme effréné.
  • il consomme très peu de bande passante (après le chargement initial)
  • il a un encombrement relativement faible (après AOT y tree shaking )--et cette empreinte continue de se réduire
  • il est hautement fonctionnel, et l'équipe et la communauté Angular poursuivent la croissance rapide de son écosystème
  • il s'adapte parfaitement à un grand nombre des meilleures et des plus récentes technologies Web, telles que TypeScript y Observables
  • Angular 5 prend désormais en charge les travailleurs de service ( https://medium.com/@webmaxru/a-new-angular-service-worker-creating-automatic-progressive-web-apps-part-1-theory-37d7d7647cc7 )
  • étant soutenu par Google il est probable qu'il sera soutenu et amélioré à l'avenir.

J'aimerais beaucoup utiliser Angular 2/4/5/6 pour mon projet actuel. Si je suis en mesure d'utiliser Angular 2/4/5/6 J'utiliserai également Angular-CLI et probablement Angular Universal (pour le rendu côté serveur).

Voici mes réflexions, jusqu'à présent, concernant les questions ci-dessus. Nous vous invitons à consulter ce site et à nous faire part de vos commentaires et de vos idées.

  • Angular 2/4/5/6 Les applications consomment des paquets - mais ce n'est pas nécessairement la même chose que d'autoriser les plugins dans une application. Un plugin dans d'autres systèmes (par ex. Drupal ) peuvent être ajoutés essentiellement en déposant le dossier du plugin dans un répertoire commun de modules où il est automatiquement "récupéré" par le système. Dans Angular 2/4/5/6 un paquet (comme peut l'être un plugin) est généralement installé par l'intermédiaire de npm ajouté à la package.json et ensuite importé manuellement dans l'application - comme dans app.module . C'est beaucoup plus compliqué que le Drupal méthode permettant de déposer un dossier et de faire en sorte que le système détecte automatiquement le paquet. Plus l'installation d'un plugin est compliquée, moins les gens seront enclins à l'utiliser. Ce serait bien mieux s'il y avait un moyen de Angular 2/4/5/6 pour détecter et installer automatiquement les plugins. Je suis très intéressé de trouver une méthode qui permette aux non-développeurs d'installer les Angular 2/4/5/6 et installer les plugins choisis sans avoir à comprendre toute l'architecture de l'application.

  • En général, l'un des avantages d'une architecture enfichable est qu'il est très facile pour les développeurs tiers d'étendre la fonctionnalité du système. Évidemment, ces développeurs ne connaissent pas toutes les subtilités du code de l'application à laquelle ils se connectent. Une fois les plugins développés, d'autres utilisateurs encore moins techniques peuvent simplement installer l'application et les plugins sélectionnés. Cependant, Angular 2/4/5/6 est relativement compliqué et sa courbe d'apprentissage est très longue. Pour compliquer encore les choses, la plupart des productions Angular 2/4/5/6 Les applications utilisent également Angular-CLI , Angular Universal y WebPack . Une personne qui implémente un plugin devra probablement avoir au moins une connaissance de base de la façon dont tous ces éléments s'assemblent, ainsi qu'une solide connaissance pratique de la technologie de l'information. TypeScript et une familiarité raisonnable avec NodeJS . Les exigences en matière de connaissances sont-elles si extrêmes qu'aucune tierce partie ne voudrait jamais développer un plugin ?

  • La plupart des plugins auront probablement un composant côté serveur (par exemple, pour stocker/récupérer les données relatives au plugin) ainsi qu'une sortie côté client. Angular 2/4/5 déconseille expressément (et fortement) aux développeurs d'injecter leurs propres modèles au moment de l'exécution, car cela présente un risque sérieux pour la sécurité. Afin de gérer de nombreux types de sortie qu'un plugin peut accueillir (par exemple, l'affichage d'un graphique), il semble que permettre aux utilisateurs de créer du contenu qui est injecté dans le flux de réponse, sous une autre forme, est probablement nécessaire. Je me demande comment il serait possible de répondre à ce besoin sans déchirer figurativement Angular 2/4/5/6 Les mécanismes de sécurité de l'UE.

  • La plupart des productions Angular 2/4/5/6 sont précompilées en utilisant Ahead of Time ( AOT ) compilation. (Je ne suis pas certain de la manière dont les plugins peuvent être ajoutés (ou intégrés) aux applications précompilées. Le meilleur scénario serait de compiler les plugins séparément de l'application principale. Cependant, je ne sais pas comment faire pour que cela fonctionne. Une solution de rechange pourrait être de recompiler l'application entière avec tous les plugins inclus, mais cela complique un peu les choses pour un utilisateur administratif qui veut simplement installer l'application (sur son propre serveur) avec les plugins sélectionnés.

  • Dans un Angular 2/4/5/6 Dans une application, surtout si elle est précompilée, un seul morceau de code errant ou conflictuel peut briser l'ensemble de l'application. Angular 2/4/5/6 ne sont pas toujours les plus faciles à déboguer. L'utilisation de plugins mal conçus peut entraîner des expériences très désagréables. Je n'ai actuellement pas connaissance d'un mécanisme permettant de gérer de manière élégante les plugins qui se comportent mal.

1 votes

A mon avis, un module angulaire 2 est un plugin. @angular/router, @angular/forms, @angular/http, @angular/material, ce sont des 'plugins' d'angular, nous pouvons vérifier comment ils font des 'plugins'.

9 votes

@Timathon, malheureusement, ce ne sont pas les mêmes. Les systèmes de plugins permettent d'étendre une application sans modifier le code de l'application de base. L'utilisation de @angular/router, @angular/forms, etc. nécessite que l'utilisateur modifie l'application. Il s'agit en fait de bibliothèques, et non de plugins. Je suis vraiment plus intéressé par le fait de permettre aux utilisateurs administratifs non développeurs de sélectionner et d'utiliser les plugins qui sont les plus intéressants pour eux sans avoir à connaître les détails internes de l'application.

1 votes

Vous avez réussi à faire quelque chose avec ça ? Je suis intéressé à essayer quelque chose de similaire. La façon dont Angular 2 est construit (autour des modules), j'ai pensé qu'une architecture de type plugin serait très bien adaptée, mais il ne semble pas y avoir d'exemples, etc.

17voto

Lars Meijdam Points 456

J'ai créé un dépôt sur github avec une solution qui pourrait aider. Elle utilise les bibliothèques Angular 6 et les applications de base 1 qui chargent les bibliothèques groupées UMD paresseusement ; https://github.com/lmeijdam/angular-umd-dynamic-example

Si vous avez des suggestions, n'hésitez pas à les ajouter !

2 votes

Comme mentionné dans un autre commentaire, j'ai dû rendre le référentiel privé en raison de la politique de l'entreprise . Je le remettrai en ligne ultérieurement car les discussions sont en cours.

0 votes

J'aimerais beaucoup voir votre solution, s'il vous plaît.

0 votes

@Subhan, je suis actuellement occupé à réécrire le référentiel avant de le remettre sur GH. Donnez-moi un peu plus de temps. Sinon, vous pouvez aussi me contacter directement ! :D

13voto

Denys Vuika Points 341

Je viens de publier un nouveau chapitre pour mon livre " Développer avec Angular "qui aborde le sujet des plugins dans Angular 2+ et devrait être d'un grand intérêt pour les personnes qui essaient de créer des plugins externes.

Points clés :

  • Plugins
  • Construction de composants à partir de noms de chaînes
  • Chargement de la configuration à partir de sources externes
  • Changement dynamique des routes d'application
  • Plugins externes
  • Création de bibliothèques de plugins
  • Chargement des plugins dans l'application
  • Itinéraires dynamiques avec le contenu des plugins

Le livre est gratuit, et son modèle est "payez ce que vous voulez". N'hésitez pas à vous en procurer un exemplaire, en espérant que cela vous aidera.

0 votes

Comment puis-je remplacer un sous-composant par l'architecture de votre plugin illustrée dans le livre ? Je vais remplacer le modèle ou peut-être je vais ajouter une propriété d'entrée ecc.... En même temps, j'ai besoin de savoir s'il existe un moyen de remplacer/étendre un service fourni.

1 votes

@Denis Vuyka, Le livre a l'air bien mais il manque la partie cruciale - le support de la compilation AoT.

7voto

Niklas Teich Points 81

Exemple d'application avec un système de plugins fonctionnel (merci à Gijs d'avoir créé le repo github !) https://github.com/PacktPublishing/Mastering-Angular-2-Components/tree/master/angular-2-components-chapter-10 basé sur l'eBook Maîtriser les composants Angular 2

  • architecture de plugins pour étendre les composants de base de l'application
  • système de plugins de fichiers (pour ajouter simplement des répertoires/fichiers de plugins sans modifier les fichiers de configuration du noyau ni devoir recompiler votre application !)
  • charger et utiliser dynamiquement les plugins
  • construction d'un gestionnaire de plugins rudimentaire pour activer/désactiver les plugins à la volée

A la vôtre, Niklas

2 votes

Je ne peux pas voir le code d'exemple de ce lien, pouvez-vous poster un Code Pen ou JSFiddle ?

4 votes

J'ai lu le livre, mais la partie plugin est dépassée. Il utilise plain JS et SystemJS, alors qu'Angular vise Typescript et Webpack. En utilisant Webpack et Typescript cela semble irréalisable, j'ai posté une question au cas où vous auriez trouvé des solutions. Voici la lien

5voto

Tom I Points 115

Ce que vous recherchez, c'est le chargement paresseux des modules. En voici un exemple : 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;
    }
  }
}

Le meilleur...Tom

17 votes

Merci d'avoir pris le temps de répondre à ma question. Je connais les modules chargés paresseusement, mais ce n'est pas tout à fait ce que je recherche. Les modules chargés paresseusement doivent toujours être connus au moment de la conception. Je souhaite pouvoir ajouter des modules et des fonctionnalités qui n'étaient pas connus ou envisagés au moment de la conception de l'application originale. (Ce que je recherche, c'est quelque chose d'un peu plus dynamique.) Ces composants utiliseraient certainement (une certaine forme de) chargement paresseux, mais ce n'est qu'une petite pièce du puzzle. Merci encore d'avoir partagé cette réponse.

1 votes

Je suis d'accord que cela ne répond pas à la question. Le chargement paresseux n'aide pas à l'architecture des plugins car ils sont nécessaires au moment de la conception. Il ne télécharge/transfère simplement pas les données vers le client avant qu'elles ne soient nécessaires.

0 votes

Et si votre application connaissait tous les modules d'extension disponibles au moment de la compilation ? Au moment où vous ajoutez un nouveau module à la plate-forme, elle doit être recompilée avec ce module. C'est juste une idée... Je ne suis pas sûr que cela augmentera la taille des fichiers JS de manière significative, je ne suis pas sûr que la fonction de chargement paresseux mettra un tel module dans un fichier séparé et le chargera ensuite paresseusement, je partage juste mon idée...

2voto

J'ai fait un hack pour charger et compiler d'autres modules au moment du bootstrap, mais je n'ai pas résolu le problème des dépendances cycliques.

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

puis dans AppModule ajouter ceci :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X