Maison  >  Article  >  interface Web  >  La conception d'un système de plug-in JavaScript est extrêmement importante

La conception d'un système de plug-in JavaScript est extrêmement importante

coldplay.xixi
coldplay.xixiavant
2020-09-02 17:26:372023parcourir

La conception d'un système de plug-in JavaScript est extrêmement importante

[Recommandations d'apprentissage associées : Tutoriel vidéo javascript]

WordPress a des plug-ins, jQuery a des plug-ins, il en va de même pour Gatsby , Eleventy et Vue.

Les plugins sont une fonctionnalité commune des bibliothèques et des frameworks, et pour cause : ils permettent aux développeurs d'ajouter des fonctionnalités de manière sûre et extensible. Cela rend le projet principal plus précieux et crée une communauté, le tout sans ajouter de charge de maintenance supplémentaire. Très bien!

Alors, comment construire un système de plug-ins ? Créons notre propre plugin en JavaScript pour répondre à cette question.

Créons un système de plugins

Commençons par un exemple de projet appelé BetaCalc. BetaCalc se veut une calculatrice JavaScript minimaliste à laquelle d'autres développeurs peuvent ajouter des « boutons ». Voici un code de démarrage de base :

// 计算器const betaCalc = {  currentValue: 0,
  
  setValue(newValue) {    this.currentValue = newValue;    console.log(this.currentValue);
  },
  
  plus(addend) {    this.setValue(this.currentValue + addend);
  },
  
  minus(subtrahend) {    this.setValue(this.currentValue - subtrahend);
  }
};// 使用计算器betaCalc.setValue(3); // => 3betaCalc.plus(3);     // => 6betaCalc.minus(2);    // => 4复制代码

Nous définissons une calculatrice comme une chose objective pour simplifier les choses, une calculatrice fonctionne en console.log imprimant le résultat.

Actuellement, la fonctionnalité est vraiment limitée. Nous avons une méthode setValue qui accepte un numéro et l'affiche sur "l'écran". Nous avons également des méthodes d'addition (plus) et de soustraction (minus), qui effectueront une opération sur la valeur actuellement affichée.

Il est maintenant temps d’ajouter plus de fonctionnalités. Créez d’abord un système de plugins.

Le plus petit système de plugins au monde

Nous commencerons par créer une méthode d'enregistrement (register) que d'autres développeurs peuvent utiliser pour enregistrer des plugins avec BetaCalc. Ce que fait cette méthode est simple : récupérez le plugin externe, récupérez sa fonction exec et attachez-la à notre calculatrice en tant que nouvelle méthode :

// 计算器const betaCalc = {  // ...其他计算器代码在这里

  register(plugin) {    const { name, exec } = plugin;    this[name] = exec;
  }
};复制代码

Voici un exemple de plugin pour notre calculatrice A "square(squared)" est fourni :

// 定义插件const squaredPlugin = {  name: 'squared',  exec: function() {    this.setValue(this.currentValue * this.currentValue)
  }
};// 注册插件betaCalc.register(squaredPlugin);复制代码

Dans de nombreux systèmes de plug-ins, les plug-ins sont généralement divisés en deux parties :

  1. Code à exécuter
  2. Métadonnées (par exemple nom, description, numéro de version, dépendances, etc.)

Dans notre plugin, la fonction exec contient notre code et name est nos métadonnées. Une fois le plugin enregistré, la fonction exec sera attachée directement à notre objet betaCalc en tant que méthode, donnant accès au this de BetaCalc.

Désormais, BetaCalc dispose d'un nouveau bouton "carré" appelable directement :

betaCalc.setValue(3); // => 3betaCalc.plus(2);     // => 5betaCalc.squared();   // => 25betaCalc.squared();   // => 625复制代码

Ce système présente de nombreux avantages. Le plugin est un simple objet littéral qui peut être transmis à nos fonctions. Cela signifie que les plugins peuvent être téléchargés via npm et importés en tant que modules ES6. La facilité de distribution est extrêmement importante !

Mais notre système présente quelques défauts.

En donnant aux plugins this accès à BetaCalc, ils peuvent avoir un accès en lecture/écriture à tout le code de BetaCalc. Bien que cela soit utile pour obtenir et configurer currentValue, cela peut également être dangereux. Si un plugin devait redéfinir des fonctions internes (comme setValue), cela pourrait produire des résultats inattendus pour BetaCalc et d'autres plugins. Cela viole le principe ouvert-fermé, qui stipule qu'une entité logicielle doit être ouverte à l'extension, mais fermée à la modification.

De plus, la fonction « au carré » fonctionne en produisant des effets secondaires. Ce n'est pas rare en JavaScript, mais cela n'est pas agréable, surtout lorsque d'autres plugins peuvent être dans le même état interne. Une approche plus pratique contribuerait grandement à rendre nos systèmes plus sûrs et plus prévisibles.

Meilleure architecture de plug-in

Jetons un coup d'œil à une meilleure architecture de plug-in. L'exemple suivant modifie à la fois la calculatrice et l'API de son plugin :

// 计算器const betaCalc = {  currentValue: 0,
  
  setValue(value) {    this.currentValue = value;    console.log(this.currentValue);
  }, 
  core: {    'plus': (currentVal, addend) => currentVal + addend,    'minus': (currentVal, subtrahend) => currentVal - subtrahend
  },  plugins: {},    

  press(buttonName, newVal) {    const func = this.core[buttonName] || this.plugins[buttonName];    this.setValue(func(this.currentValue, newVal));
  },

  register(plugin) {    const { name, exec } = plugin;    this.plugins[name] = exec;
  }
};  
// 我们得插件,平方插件const squaredPlugin = { 
  name: 'squared',  exec: function(currentValue) {    return currentValue * currentValue;
  }
};

betaCalc.register(squaredPlugin);// 使用计算器betaCalc.setValue(3);      // => 3betaCalc.press('plus', 2); // => 5betaCalc.press('squared'); // => 25betaCalc.press('squared'); // => 625复制代码

Nous avons apporté quelques modifications notables ici.

Tout d'abord, nous séparons le plugin des méthodes de calcul "de base" (telles que plus et moins) en les plaçant dans leur propre objet plugin. Stocker nos plugins dans des objets plugins rend notre système plus sécurisé. Désormais, les plugins accédant à ce plugin ne verront pas l'attribut BetaCalc, mais uniquement l'attribut betaCalc.plugins.

Deuxièmement, nous implémentons une méthode press qui recherche la fonction du bouton par son nom, puis l'appelle. Désormais, lorsque nous appelons la fonction exec du plugin, nous transmettons la valeur actuelle de la calculatrice (currentValue ) à la fonction et nous nous attendons à ce qu'elle renvoie la nouvelle valeur de la calculatrice.

Essentiellement, cette nouvelle press méthode convertit tous les boutons de notre calculatrice en fonctions pures. Ils prennent une valeur, effectuent une opération et renvoient le résultat. Cela présente de nombreux avantages :

  • Cela simplifie l'API.
  • Cela facilite les tests (à la fois pour BetaCalc et pour le plugin lui-même).
  • Cela réduit les dépendances de notre système et le rend plus lâchement couplé.

Cette nouvelle architecture est plus limitée que le premier exemple, mais fonctionne bien. Nous avons essentiellement mis en place des garde-fous pour les auteurs de plugins, les limitant à apporter uniquement les modifications que nous souhaitons qu'ils apportent.

En fait, c'est peut-être trop strict ! Pour le moment, notre plugin de calculatrice ne fonctionne que sur currentValue. Si un auteur de plugin souhaite ajouter des fonctionnalités avancées (telles qu'un bouton « Mémoriser » ou un moyen de suivre l'historique), il ne peut pas faire grand-chose.

Peut-être que c'est bien. Le pouvoir que vous accordez aux auteurs de plugins est un équilibre délicat. Leur donner trop de puissance peut affecter la stabilité de votre projet. Mais si vous leur donnez trop peu de puissance, il leur sera difficile de résoudre leurs propres problèmes, auquel cas autant ne pas se brancher.

Que pouvons-nous faire d'autre ?

Nous avons encore beaucoup de travail à faire pour améliorer notre système.

Nous pouvons ajouter une gestion des erreurs pour avertir l'auteur du plugin s'il oublie de définir un nom ou une valeur de retour. Il est bon de penser comme un développeur QA et d'imaginer comment nos systèmes pourraient tomber en panne afin de pouvoir gérer ces situations de manière proactive.

Nous pouvons étendre les fonctionnalités du plugin. Actuellement, un plugin BetaCalc peut ajouter un bouton. Mais que se passerait-il s’il pouvait également enregistrer des rappels pour certains événements du cycle de vie (comme lorsque la calculatrice est sur le point d’afficher une valeur) ? Ou s'il existait un endroit dédié pour stocker un élément d'état à travers plusieurs interactions ? Cela ouvrira-t-il de nouveaux cas d’utilisation ?

Nous pouvons également étendre la fonction d'enregistrement du plug-in. Et si un plugin pouvait être enregistré avec une configuration initiale ? Est-ce que cela rend le plugin plus flexible ? Que se passerait-il si un auteur de plugin souhaitait enregistrer un ensemble complet de boutons au lieu d'un seul bouton - comme « BetaCalc Stats Package » ? Quels changements doivent être apportés pour soutenir cela ?

Votre système de plug-ins

BetaCalc et son système de plug-ins sont très simples. Si votre projet est plus vaste, vous souhaiterez explorer d'autres architectures de plugins.

Un bon point de départ est d'examiner les projets existants pour trouver des exemples de systèmes de plugins réussis. Pour JavaScript, cela peut signifier jQuery, Gatsby, D3, CKEditor ou autres. Vous souhaiterez peut-être également vous familiariser avec les différents modèles de conception JavaScript, chacun fournissant des interfaces et des degrés de couplage différents, vous offrant ainsi de nombreux bons choix architecturaux de plugins. Comprendre ces options peut vous aider à mieux équilibrer les besoins de toutes les personnes qui utilisent votre projet.

En plus des modèles eux-mêmes, il existe de nombreux bons principes de développement logiciel sur lesquels vous pouvez vous appuyer pour prendre de telles décisions. J'ai déjà mentionné quelques approches (telles que le principe ouvert-fermé et le couplage lâche), mais d'autres approches connexes incluent la loi de Déméter et l'injection de dépendances.

Je sais que cela semble beaucoup, mais vous devez faire vos recherches. Il n'y a rien de plus pénible que de demander à chacun de réécrire son plugin car vous devez changer l'architecture du plugin. C’est un moyen rapide de perdre confiance et de faire perdre confiance aux gens dans leurs contributions futures.

Résumé

Écrire une bonne architecture de plugin à partir de zéro est difficile ! Vous devez équilibrer de nombreuses considérations pour construire un système qui répond aux besoins de chacun. Est-ce assez simple ? La fonction peut-elle être puissante ? Est-ce que ça fonctionnera à long terme ?

Mais ça vaut le coup, avoir un bon système de plug-ins aide tout le monde et les développeurs peuvent résoudre leurs problèmes librement. Il existe un grand nombre de fonctionnalités optionnelles parmi lesquelles les utilisateurs finaux peuvent choisir. Vous pouvez construire un écosystème et une communauté autour de votre projet. C'est une situation gagnant-gagnant.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer