Si vous utilisez Video.js depuis un certain temps, vous connaissez sans doute le concept des plugins : des fonctions qui deviennent des méthodes de n'importe quel lecteur que vous créez. Si vous n'êtes pas familier avec les plugins Video.js, nous avons mis à votre disposition un guide complet sur les plugins.
Ces plugins, que nous appellerons plugins de base, sontlégers et offrent un contrôle complet du lecteur. C'est très utile et cela ne change pas.
Mais qu'en est-il si vous souhaitez disposer d'un ensemble de fonctionnalités plus riche ? Ou plus de conseils sur la façon de structurer votre plugin ? Ou plus d'outils prêts à l'emploi pour aider à gérer des lecteurs complexes riches en plugins ?
Jusqu'à Video.js 6.0, vous deviez vous débrouiller tout seul.
Présentation des plugins avancés
L'une des forces de Video.js est son riche écosystème de plugins. C'est pourquoi, au cours des derniers mois, nous avons voulu concentrer nos efforts sur l'amélioration de l'expérience des auteurs de plugins.
Alors que des projets tels que le générateur de plugins facilitent plus que jamais la création de plugins, l'équipe de Video.js a estimé qu'il était important de fournir une API de base et un ensemble de conventions sur lesquels l'avenir des plugins Video.js pourrait être construit.
Notre solution consiste à utiliser des plugins avancés.
Les plugins avancés s'apparentent à des composants
L'un des objectifs de la conception des plugins avancés était de fournir une API qui rappelle le système de composants existant. Nous y sommes parvenus de plusieurs manières.
Au niveau le plus bas, il s'agit d'un changement de nom pour la fonction d'enregistrement des plugins, qui passe de videojs.plugin
à videojs.registerPlugin
(en s'inspirant de l'appellation videojs.registerComponent
et videojs.registerTech
).
Au-delà d'un simple changement de nom de la méthode d'enregistrement, les plugins avancés sont basés sur des classes. Un exemple trivial de plugin avancé pourrait ressembler à ceci :
var Plugin = videojs.getPlugin('plugin');
var HelloWorld = videojs.extend(Plugin, {
constructor(player) {
Plugin.call(this, player);
this.player.addClass('hello-world');
}
});
videojs.registerPlugin('helloWorld', HelloWorld);
Si vous utilisez un transpileur ES6, vous pouvez utiliser les classes ES6 de la même manière.
Ce plugin peut être initialisé de la même manière qu'un plugin de base, par le biais d'une méthode de lecteur dont le nom correspond au nom enregistré du plugin.
Dans le cas des plugins avancés, cette méthode est une fonction d'usine, qui instancie la classe du plugin et renvoie une instance.
Il est utile de savoir que la méthode du lecteur créée sera toujours une fonction. Si un lecteur possède déjà une instance d'un plugin avancé, sa méthode associée renverra simplement l'instance préexistante plutôt que de la réinitialiser :
var player = videojs('my-player');
var instance = player.helloWorld();
// Logs: 'true'
videojs.log(instance === player.helloWorld());
Le helloWorld
renverra cet objet plugin jusqu'à ce qu'il soit éliminé, après quoi elle créera à nouveau une nouvelle instance de plugin.
Evénements
Comme les composants, les plugins avancés peuvent écouter et déclencher des événements par l'intermédiaire de la fonction on
, one
, off
et trigger
des méthodes.
Cela permet aux plugins et aux autres objets (composants, lecteurs, etc.) de gérer leur propre état et de répondre aux changements d'état des uns et des autres par le biais d'un canal de communication faiblement couplé.
Données supplémentaires sur les événements
Le système d'événements Video.js permet de transmettre des données supplémentaires aux auditeurs en tant que deuxième argument lors du déclenchement d'événements (le premier argument est l'objet de l'événement lui-même).
Les événements du plugin transmettent un ensemble cohérent de propriétés dans cet objet (y compris toutes les propriétés personnalisées transmises à l'objet trigger
) :
instance
: L'instance du plugin qui a déclenché l'événement.name
: Le nom du plugin sous forme de chaîne de caractères (par ex.'helloWorld'
).plugin
: La fonction de classe/constructeur du plugin (par ex.HelloWorld
).
Par exemple, un auditeur d'un événement sur un plugin peut s'attendre à quelque chose comme ceci :
var player = videojs('my-player');
var instance = player.helloWorld();
instance.on('some-custom-event', function(e, data) {
videojs.log(data.instance === instance); // true
videojs.log(data.name === 'helloWorld'); // true
videojs.log(data.plugin === videojs.getPlugin('helloWorld')); // true
videojs.log(data.foo); // "bar"
});
instance.trigger('some-custom-event', {foo: 'bar'});
Cycle de vie
Une autre similitude entre les plugins et les composants est le concept de cycle de vie - plus précisément, les processus d'installation et de démontage.
La fonction de configuration est un effet secondaire de la création normale d'objets en JavaScript, mais nous sommes laissés à nous-mêmes lorsqu'il s'agit de détruire des objets et de veiller à ce que les références entre objets soient nettoyées pour éviter les fuites de mémoire.
Les composants Video.js ont depuis longtemps une fonction dispose
qui traitent de la suppression d'un composant du DOM et de la mémoire. Les plugins avancés disposent de la même fonctionnalité :
var player = videojs('my-player');
var firstInstance = player.helloWorld();
// Logs: 'true'
videojs.log(firstInstance === player.helloWorld());
firstInstance.on('dispose', function() {
videojs.log('disposing a helloWorld instance');
});
// Logs: 'disposing a helloWorld instance'
firstInstance.dispose();
var secondInstance = player.helloWorld();
// Logs: 'false'
videojs.log(firstInstance === secondInstance);
Le pluginsetup
Événement
Les plugins ont une caractéristique du cycle de vie que les composants n'ont pas : la fonction pluginsetup
événement.
Cet événement est déclenché sur un lecteur lorsqu'un plugin est initialisé sur celui-ci :
var player = videojs('my-player');
player.on('pluginsetup', function(e, hash) {
if (hash.name === 'helloWorld') {
videojs.log('A helloWorld instance was created!');
}
});
// Logs: 'A helloWorld instance was created!'
player.helloWorld();
L'état de santé inspiré de React
L'une des nouveautés les plus intéressantes de Video.js, tant pour les plugins avancés que pour les composants, est l'état d'avancement (statefulness) inspiré de React. Essentiellement, cela signifie que tous les objets des plugins et des composants ont un état state
qui est un objet simple pouvant être utilisé pour stocker l'état des variables de cet objet. Ensuite, il y a un setState
qui met à jour cet objet et déclenche une statechanged
événement.
Ce système permet aux plugins et aux composants d'utiliser leur nature événementielle pour communiquer les changements d'état en mémoire par le biais d'une API cohérente :
// A static property of the constructor can be used to pre-populate state
// for all instances.
HelloWorld.defaultState = {color: 'red'};
var player = videojs('my-player');
var instance = player.helloWorld();
instance.on('statechanged', function(e) {
var color = e.changes.color;
if (color) {
videojs.log('The helloWorld color changed from "' + color.from + '" to "' + color.from + '"!');
}
});
// Logs: 'The helloWorld color changed from "red" to "blue"!'
instance.setState({color: 'blue'});
Sensibilisation au plugin du lecteur
Enfin, nous ne pouvions pas ajouter une nouvelle infrastructure de plugins sans travailler sur l'un des problèmes les plus pernicieux de la gestion de combinaisons complexes de plugins : le lecteur ne peut pas signaler les plugins qu'il a initialisés - ou non. À cette fin, le lecteur dispose de deux nouvelles méthodes : hasPlugin
et usingPlugin
. Ces méthodes fonctionnent pour à la fois types de plugins.
Le hasPlugin
Méthode
Cette méthode indique si un plugin correspondant à un nom donné est disponible sur le lecteur :
var player = videojs('my-player');
// Logs: 'true'
videojs.log(player.hasPlugin('helloWorld'));
// Logs: 'false'
videojs.log(player.hasPlugin('fooBar'));
Cette méthode ignore si le plugin a été initialisé ou non et indique simplement s'il a été enregistré ou non.
Le usingPlugin
Méthode
Cette méthode indique non seulement si un plugin est disponible sur un lecteur, mais aussi s'il est actuellement actif sur le lecteur :
var player = videojs('my-player');
// Logs: 'false'
videojs.log(player.usingPlugin('helloWorld'));
player.helloWorld();
// Logs: 'true'
videojs.log(player.usingPlugin('helloWorld'));
Une mise en garde s'impose : bien que cela fonctionne pour les deux types de plugins, seuls les plugins avancés peuvent modifier cette valeur plus d'une fois. Un plugin de base n'a pas de cycle de vie intégré ni d'événements, il n'est donc pas possible de déterminer s'il a été "éliminé".
Allez-y et codez
Nous espérons que ces ajouts et améliorations à l'architecture des plugins rendront l'écriture de plugins Video.js plus agréable et supprimeront une partie du travail de bas niveau nécessaire pour s'assurer que les plugins ne créent pas de fuites de mémoire et d'autres problèmes.
La conception des plugins avancés est telle que nous pouvons ajouter des fonctionnalités au fur et à mesure que la version 6.0 mûrit et que nous recevons davantage de commentaires de la part de la communauté. Comme toujours, nous encourageons vivement nos utilisateurs à contribuer au projet Video.js par tous les moyens possibles.
Cet article a été publié à l'origine sur le blog Video.js.