vueuse / head

Document head management for Vue. Powered by Unhead. - 🌇 Sunset

Home Page:https://unhead.unjs.io/setup/vue/installation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`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 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())
  }
})

The hook can be helpful for more complex scenarios for sure 👍🏻

Ah good question, feel free to experiment yourself :P

https://stackblitz.com/edit/vue-2uniew?file=src/App.vue

@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 ❤️