Note: Advanced plugins are being introduced in Video.js 6.0 and are only supported from that version forward.
If you’ve been a Video.js user for a while, you’re likely familiar with the concept of plugins: functions that become methods of any player you create. If you’re not familiar with Video.js plugins, we have a comprehensive plugins guide available.
These plugins - which we’ll call basic plugins - are lightweight and offer complete control of the player. That’s really useful and it isn’t changing - existing plugins should continue to work!
But what if you want a richer set of features? Or more guidance on how to structure your plugin? Or more tools out of the box that help manage complex plugin-rich players?
Well, until Video.js 6.0, you had to figure things out on your own.
One of Video.js’ strengths is its rich ecosystem of plugins; so, in the last few months, we wanted to focus our efforts on improving the plugin author experience.
While projects like the plugin generator and videojs-spellbook make becoming a plugin author easier than ever, the Video.js team thought it was important to provide a foundational API and set of conventions on which the future of Video.js plugins could be built.
Our solution is advanced plugins.
One of the design goals for advanced plugins was to provide an API that was reminiscent of the existing components system. We achieved this in a number of ways.
At the lowest level, this included a name change for the plugin registration function from
videojs.registerPlugin (taking a naming cue from
Beyond a simple registration method name change, advanced plugins are class-based. A trivial example of an advanced plugin might look something like this:
This plugin can be initialized in the same way as a basic plugin - via a player method whose name matches the registered name of the plugin.
In the case of advanced plugins, this method is a factory function, which instantiates the plugin class and returns an instance.
It’s useful to know that the player method that is created will always be a function. If a player already has an instance of an advanced plugin, its associated method will simply return the pre-existing instance rather than re-initialize it:
helloWorld method will return this plugin object until it is disposed - after which it will create a new plugin instance again.
Similar to components, advanced plugins can listen to and trigger events via the
This provides a loosely coupled communication channel for plugins and other objects (components, players, etc) to manage their own state and respond to changes in the state of one another.
The Video.js event system allows additional data to be passed to listeners as a second argument when triggering events (the first argument is the event object itself).
Plugin events pass a consistent set of properties in this object (including any custom properties passed to
instance: The plugin instance, which triggered the event.
name: The name of the plugin as a string (e.g.
plugin: The plugin class/constructor function (e.g.
For example, a listener for an event on a plugin can expect something like this:
Another similarity between plugins and components is the concept of a lifecycle - more specifically, setup and teardown processes.
Video.js components have long had a
dispose method and event that deal with removing a component from the DOM and memory. Advanced plugins have the same feature:
Plugins do have one lifecycle feature that components do not: the
This event is triggered on a player when a plugin is initialized on it:
One of the exciting additions in Video.js for both advanced plugins and components is React-inspired statefulness. Essentially, this means that all plugin objects and component objects have a
state property, which is a plain object that can be used to store variable state for that object. Then, there is a
setState method that updates this object and triggers a
This system allows plugins and components to use their evented nature to communicate in-memory state changes through a consistent API:
Finally, we couldn’t add new plugin infrastructure without working on one of the more pernicious problems of managing complex combinations of plugins: the player can’t report which plugins it has initialized - or not. To this end, the player has two new methods:
usingPlugin. These methods work for both types of plugins.
This method reports whether a plugin matching a given name is available on the player:
This method ignores whether or not the plugin has been initialized and merely reports whether or not it has been registered.
This method reports not only whether a plugin is available on a player, but whether it is currently active on the player:
One caveat to note here. While this works for both types of plugins, only advanced plugins can change this value more than once. A basic plugin has no built-in lifecycle or events; so, it’s not possible to determine whether one has been “disposed”.
We hope these additions and improvements to the plugin architecture will make writing Video.js plugins more pleasurable and remove some of the low-level legwork involved in ensuring plugins aren’t creating memory leaks and other problems.
The design of advanced plugins is such that we can add features as 6.0 matures and we get more community feedback. As always, we strongly encourage our users to give back to the Video.js project in whatever way they can.
For a more complete discussion of plugins generally, visit the Video.js plugins guide.