destroying before removing element causes error with youtube
See original GitHub issueThis may not be an “issue” but any guidance would be helpful.
Expected behaviour
Using Plyr.js destroy method in Vue.js component lifecycle hooks should destroy Plyr instance before component is destroyed.
Actual behaviour
My app uses Plyr for two types of sources: HLS and YouTube.
I load Plyr inside of a Vue.js component and destroy it by calling instance.destroy()
when the component is unloaded in its beforeDestroy
lifecycle hook. This is how I used Plyr in v2 and it worked fine. Please note that Vue.js lifecycle hooks are synchronous and they are not interested in changing that at the moment.
Now, however, YouTube instances can’t be destroyed without an error:
vue.runtime.esm.js?ff9b:1683 Error: The YouTube player is not attached to the DOM.
at Y.h.B (www-widgetapi.js:99)
at X (www-widgetapi.js:91)
at Y.(anonymous function).getCurrentTime.cb.(anonymous function) [as stopVideo] (https://s.ytimg.com/yts/jsbin/www-widgetapi-vflQSvpsZ/www-widgetapi.js:109:124)
at HTMLDivElement.player.media.stop (youtube.js?6edf:285)
at plyr_Plyr.stop (plyr.js?1bb6:403)
at plyr_Plyr.destroy (plyr.js?1bb6:1078)
at VueComponent.beforeDestroy (video-player.vue?53d5:335)
at callHook (vue.runtime.esm.js?ff9b:2813)
at VueComponent.Vue.$destroy (vue.runtime.esm.js?ff9b:2598)
at destroy (vue.runtime.esm.js?ff9b:4027)
A breakpoint in the YouTube plugin’s stop method shows that the player DOM has been unloaded by Vue long before we get to this stop call.
The HLS.js plyr appears to destroy fine.
Guarding the call to this.media.stop
inside destroy
kept YouTube to check if the plyr was playing didn’t prevent the error. It also caused the timeupdate
event to continue firing on the HLS version.
if (this.playing) {
this.stop();
}
At first I thought this must be due to the destroy
method being asynchronous in v3, but I’m not sure if that’s the case for all source types.
Not sure where to go next. There’s an async hook farther up in the application structure that I may be able to wire plyr into, but it would be a shame to not have the ability to wrap the plugin in a reusable component like I could before.
I am not using [https://github.com/redxtech/vue-plyr] but as of writing it looks like they have a similar issue: https://github.com/redxtech/vue-plyr/issues/9
Environment
- Browser: Chrome
- Version: 66
- Operating System: Mac OS
- Version: 10.13.4
Steps to reproduce
- Make a plyr instance in a Vue.js component with YouTube as a source
- Destroy the instance in the
beforeDestroy
hook of the component - Make parent component(s) for testing
- Put the plyr component inside of the parents
- Destroy the parent component.
- See error.
Issue Analytics
- State:
- Created 5 years ago
- Comments:17
Top GitHub Comments
@qikkeronline This type of comment is discouraged in the FAQ and contribution guidelines. Anyone has the right to fork Plyr, fix this issue and submit a PR. No one has, and afaik no one is working on it.
I think (at least hope) my previous comment is helpful if someone wants to have a try. Speaking of “try”, the simples solution is probably adding a try/catch somewhere in the code or wrapping your
destroy()
calls.I’m no longer helping out with Plyr development so I’m going to unsubscribe (so @mention me if you need to reach me).
Update: You can dislike this all you want. Doesn’t change anything.
Youtube and Vimeo events are async.
destroy()
restores the element to how it was before Plyr transformed it (removes event listeners and Plyr elements). It also stops the media playback. With youtube you may not have any original element (see the part about “progressive enhancement”: https://github.com/sampotts/plyr/#youtube-embed), in which case the error may happen (not sure), or like in your case, Vue may be removing the element before stopVideo is executed in which case this may also happen.I’d say it’s a bug on our side. We should either not
stop
fromdestroy
, add an optional argument to control it, or handle errors instop
due to being called fromdestroy
.You may not need
destroy
though, if you’re going to remove the plyr container element, and have no other references to Plyr. Event listeners and such gets destroyed along with their elements, and garbage collection kicks in when there are no more references to something.