`callback` option for loading scripts
manniL opened this issue · comments
Currently, useHead
does not provide a vue-meta-like callback
function to do something when a script has been loaded.
It'd be a nice DX feature IMO
Thanks for the suggestion, would you mind providing a real-life example? The example in Vue Meta is a bit abstract
Sure! I've outlined one in this blog post
Great, thanks.
Currently, tags let you provide the raw dom event handlers as strings, could be feasible to allow a function here instead that should be run. This would be a fairly nice DX as the side effects could be handled universally pretty easily
Thoughts?
useHead({
script: [
{
src: '<https://js.stripe.com/v3/>',
defer: true,
load: () => doSomething()
}
]
})
For a more generic approach, the dom:renderedTag
hook will be available in v1. The code isn't as nice but much more flexible
const head = injectHead()
head.hooks.hook('dom:renderedTag', ({ $el }) => {
if ($el.tag === 'SCRIPT' && $el.getAttribute('src') === 'https://js.stripe.com/v3') {
$el.addEventListener('load', () => doSomething())
}
})
Thoughts?
useHead({ script: [ { src: '<https://js.stripe.com/v3/>', defer: true, load: () => doSomething() } ] })
This looks pretty close to what I've imagined 👍🏻
One more scenario to think of though.: Imagine having a component loading a script via useHead
. If this component will be rendered once, the script will be added and loaded and the load
function will be executed eventually.
What happens if the component will be rendered again, as the script is already part of the site? 🤔
I'd assume load will be triggered again but I am not sure 🙈
For a more generic approach, the
dom:renderedTag
hook will be available in v1. The code isn't as nice but much more flexibleconst head = injectHead() head.hooks.hook('dom:renderedTag', ({ $el }) => { if ($el.tag === 'SCRIPT' && $el.getAttribute('src') === 'https://js.stripe.com/v3') { $el.addEventListener('load', () => doSomething()) } })
The hook can be helpful for more complex scenarios for sure 👍🏻
Ah good question, feel free to experiment yourself :P
@harlan-zw That was quick! 👀
But sadly, the timestamp will only be set once, after that the "loading" state will be kept, no matter if re-rendering the same component or loading the script in a second one. Ideally, it would just give out the timestamp immediately. With the current behavior, it can't be asserted reliably whether the script has been loaded (if it was loaded before already)
Ah I think there's a larger bug actually in that stackblitz setup, it's not removing the script when you click it a second time 🤔
The issue you mention is also there though, can be replicated by adding the same script in App.vue. A straightforward solution is just to set some global ref wherever you're loading the script but I might be able to tinker with it so the onload always fires
This is available in v1, documentation is here: https://unhead.harlanzw.com/guide/guides/dom-event-handling
If you insert the script client side only, then onload
is guaranteed to run as it won't set the src
until the event listener is attached
I was looking for this exact feature and am amazed it already exists ❤️