taoeffect / vue-script2

Standardized, designer-friendly <script> behavior for your Single Page App
171 stars 15 forks source link

Using with simultaneously rendered components #12

Closed rdunk closed 5 years ago

rdunk commented 7 years ago

I have a view in my app which renders multiple video player components in a v-for loop. This component uses vue-script2's promise based loading to load a remote script in the mounted() lifecycle hook.

As these components are rendered simultaneously, I notice the remote script is actually added multiple times (once for each component). I'm assuming this package doesn't perform any checks for pending scripts or anything like that? Should I be using a different method for loading these?

taoeffect commented 7 years ago

Well, on line 54 you'll see that it avoids loading files that have already been loaded, but you're right that if you try to load the same script really quickly in a row, before any one of them has finished loading, it will (currently) load the script multiple times in a row.

However, it's highly unusual to load the same <script> tag more than once. I can't think of a time I've ever seen that done.

I have seen iframes used with media players, and maybe that iframe contains a VueScript2 component in it, but in that case there's nothing (I don't think) we could do to prevent it from being loaded multiple times.

If you're not using iframes, well, I guess I'd have to see what you're trying to do. There's probably a workaround that makes more sense.

rdunk commented 7 years ago

In my specific use case, I'm rendering multiple inline videos in a single long form blog post. I'm avoiding this issue in 95% of circumstances now by lazy loading the reusable component that loads the script.

The only way I can think to avoid this by having some sort of central bus/store that queues scripts to be loaded, but that would have an unwanted performance impact as they'd need to be loaded in sequence.

taoeffect commented 7 years ago

So, I'm curious about the precise implementation that's being used. I just can't help much without knowing what you're doing.

rdunk commented 7 years ago

I'll try and describe my use case, the code should become publicly available soon so I will provide a link when it is.

I've built a Vue component for displaying videos hosted on the Brightcove video platform. Brightcove allows you to maintain a library of custom players. You can assign each player various plugins that are stored in git repositories on the platform. Brightcove compiles and minifies each player into a single js file, hosted on their platform, which you include on your page.

The code responsible for loading the player script asynchronously is triggered in the video component mounted() lifecycle hook. This is because the component accepts a 'player id' prop which means it could use one of many different video players (we use different players in different parts of the app). The player scripts are pretty large, so we don't want to load them unless absolutely necessary.

We have a 'blog post' view in the app which in some circumstances contains more than one video component, usually with the same player id. Without lazyloading, Vue could potentially render multiple video components simultaneously when this view is rendered, triggering multiple mounted() hooks and thus loading the same script multiple times.

Hope that makes sense.

vgavro commented 6 years ago

Imho it's a legit and common usecase. You may use script2 with same script in different components that appears on same page, for example country info for country input and phone input, and you really don't want to track this in parent component. I guess we can easily solve this by storing promise in Script2.loaded instead of "1", and we may even keep it after loading, so code can look like:

if (!Script2.load[src]) Script2.load[src] = Promise((resolve, reject... {
})
return Script2.load[src]

and remove Script2.loaded[src] = 1 from onload.