vueuse/head

Is there support for nuxt + vue 3

Closed this issue · 19 comments

Hello, does this support Vue 3 + Nuxt 3 ?

Thank you!

Yes, Nuxt v3 depends on this package. If you use useHead anywhere in your Nuxt app you'll be using it :)

Did you have any questions or issues with it in Nuxt?

Thank you for the answer!

Yes a help would be very good..

I am using vue + nuxt 3, latest release. Composition API

First Problem I have is that I can not acess "My Data" to make it dynamic, solved this declaring useHead after

At first I used the component like this:

import:

import { useHead } from '@vueuse/head'

 useHead({
      meta: [
        { hid: 'og-type', property: 'og:type', content: 'website' },
        { hid: 'og-title', property: 'og:title', content: `App Name - ${projectName}` },
        { hid: 'og-image', property: 'og:image', content: `${imageUrl}`},
      ]

And I don't know what else I should to configure. The metadata should be Dynamic, because on this page will be different "projects" rendered

Here is the code. (I removed some sensible data)

<script lang="ts">
import { useUserStore } from '@/store/user'
import { useHead } from '@vueuse/head'
export default defineComponent({
  name: 'PublicProjectsId',
  setup() {
    definePageMeta({
      layout: "public",
    })
    const imageUrl = ref('')
    const router = useRouter()
    const route = useRoute()
    
    const projectName = computed(() => {
      return project.value.name
    })
    const setImage = (url) => {
      imageUrl.value = url
    }
    useHead({
      meta: [
        { hid: 'og-type', property: 'og:type', content: 'website' },
        { hid: 'og-title', property: 'og:title', content: `App Name - ${projectName}` },
        { hid: 'og-image', property: 'og:image', content: `${imageUrl}`},
      ]
    })
    
 
    return {
      project,
      projectName
    }
  }
})
</script>

Thank you very much for your help, and this would definitely worth a beer :)

Sure, let me try and help you with this.

The issue you seem to be having is you're resolving the reactive data before it's sent into useHead.

Let's look at this example:

const myTitle = ref('initial title')
useHead({
  title: `${myTitle}`
})
myTitle.value = 'new title'

In this, the title would be 'initial title' no matter what happens to the ref value. To get around this, you should either provide the ref as is, a computed value, or a reactive getter.

const myTitle = ref('initial title')
useHead({
  title: myTitle
})
myTitle.value = 'new title'

This would fix it.

For your code, this is how I would personally handle it:

    useHead({
      meta: [
        { hid: 'og-type', property: 'og:type', content: 'website' },
        { hid: 'og-title', property: 'og:title', content: () => `App Name - ${project.value.name}` },
        { hid: 'og-image', property: 'og:image', content: imageUrl },
      ]
    })

The () => value is the reactive getter syntax and is your friend

If that doesn't help then I might need some more of the code, specifically around how the project is being fetched.

Also some tips:

  • you don't need to import useHead, the auto-imports should do that for you
  • you don't need to provide hid, these og props are already deduped based on the property name

Mega thank you, I will try it this evening and write an answer!

Thank you!

Hello, I have tried but it also did not work!

Same as if I use static values, I have also tried in differents components.

here is my setup code:

<script lang="ts">
import { useUserStore } from '@/store/user'

export default defineComponent({
  name: 'PublicProjectsId',

  setup() {
    definePageMeta({
      layout: "public",
    })

    const project = ref(null)
    const locations = ref([])
    const imageUrl = ref('')
    const projectContactFormModalOpen = ref(false)
    const router = useRouter()
    const snackbar = useSnackbar()

    const route = useRoute()
    const userStore = useUserStore()
    let api = usePublicApi()
    

    useHead({
      title: 'alex-test',
      meta: [
        { hid: 'og-type', property: 'og:type', content: 'website' },
        { hid: 'og-title', property: 'og:title', content: 'test-alex' },
        { hid: 'og-image', property: 'og:image',content: '' },
      ]
    })

    const handleResetLink = () => {
      if (router.currentRoute.value.path === '/') {
        location.reload()
      } else {
        router.push({ path: '/' })
      }
    }
    if (useUser().loggedIn()) {
      api = usePrivateApi()
    }


    const projectId = computed(() => {
      return route.params.id
    })

 
    onMounted(() => {
      getPublicProject()
    })

    const getPublicProject = async () => {
      try {
        const res = await api.call('get', `projects/${projectId.value}`, null)
        if (res) {
          project.value = res.data.resource
          locations.value = []
          project.value.locations.forEach((location: any) => {
            locations.value.push({
              id: project.value.id,
              longitude: parseFloat(location.longitude),
              latitude: parseFloat(location.latitude),
              draggable: false
            })
          })
          setImage(project.value.image_url)
        }
      } catch (error) {
        console.log(error)
      }
    }

    const setImage = (url) => {
      imageUrl.value = url
    }
 

    return {
      project,
      locations,
      userStore,
      setImage,
      getPublicProject,
      projectContactFormModalOpen,
      handleResetLink,
    }
  }
})
</script> 

Thank you very much again for your help :)

Could you confirm the issue in this second code example? It looks like it should work correctly, are you saying nothing is updating?

Hello, yes this is the actual code, and unfortunately it does not work. Can you say a better way to test it? Maybe my tests are wrong.

Thank you!

The code you provided has static useHead values and it looks like they are being added to that page.

If you provide a dynamic code example and push that to that URL I can help you debug further.

Perfect, I am going to do it right now and send you the changes

I have updated the code:

for projects it's now like this:

useHead({
      title: 'Smart Wendel',
      meta: [
        { property: 'og:type', content: 'website' },
        { property: 'og:title', content: () => `${project.name}` },
        { property: 'og:image', content: imageUrl },
        { property: 'og:description', content: () => `${project.excerpt}` }
      ]
    })

And in public vue:

useHead({
   title: 'Smart Wendel',
   meta: [
     { property: 'og:type', content: 'website' },
     { property: 'og:title', content: 'website'},
     { property: 'og:image', content: '' },
   ]
 })

Thank you!!

I think you're missing the .value. Looking at the site it shows those values as undefined

useHead({
      title: 'Smart Wendel',
      meta: [
        { property: 'og:type', content: 'website' },
        { property: 'og:title', content: () => `${project.value.name}` },
        { property: 'og:image', content: imageUrl },
        { property: 'og:description', content: () => `${project.value.excerpt}` }
      ]
})

Hello,

.value is already given here, it also not necessary in the place, it also doesn't work using .value

 const getPublicProject = async () => {
      try {
        const res = await api.call('get', `projects/${projectId.value}`, null)
        if (res) {
          **project.value = res.data.resource**
          locations.value = []
          project.value.locations.forEach((location: any) => {
            locations.value.push({
              id: project.value.id,
              longitude: parseFloat(location.longitude),
              latitude: parseFloat(location.latitude),
              draggable: false
            })
          })
          setImage(project.value.image_url)
        }
      } catch (error) {
        console.log(error)
      }
    }

Please understand that the issue you're having is related to your code. You are not providing data correctly.

I'm not exactly sure what you mean by this snippet, but you can see yourself that undefined is the output of what you've given.

You can see this yourself by putting console logs in the functions

useHead({
      title: 'Smart Wendel',
      meta: [
        { property: 'og:type', content: 'website' },
        { property: 'og:title', content: () => { 
                console.log(project, project.name)
              return `${project.value.name}`
             } 
        },
        { property: 'og:image', content: imageUrl },
        { property: 'og:description', content: () => `${project.value.excerpt}` }
      ]
})

Hello, thank you for the answer .. I made tests and confirm that useHead is working, means it works as it should...

In fact, the dynamic text is not working, with .value, I have also tried a workaround using computed and ref() as u said before but I get [object] [object] as value.

I also made some other tests, but no success. I have also another question, would Facebook, WhatsApp.. read those values ? Because it is only in elements, but not in the source code of the page. The only way I found to do that is in nuxt config with:

 app: {
    head: {
      charset: 'utf-16',
      viewport: 'width=500, initial-scale=1',
      title: 'My App',
      meta: [
        { property: 'og:type', content: 'website' },
        { property: 'og:title', content: 'please work' },
        { property: 'og:description', content: 'oh God' }
      ],
    }
  }

But it does not help, since I have dynamic pages and it is properties (projects).

Thank you veeery much!

If you're using SSR or SSG then they will be able to read these tags correctly. You can right click -> inspect source and you should be able to see the tags.

As an example my personal site which uses dynamic tags for the og:title has no issues: https://harlanzw.com/

Hi :)

I have Issues to enable the SSR in my project, but at least now I understand how useHead works

Thank you very much!

I have the same problem sadly.
Using an older version (e.g. 0.7.12), I do not encounter such problem, but using the latest version, the attributes won't even show up, when using SSR.

e.g.:

useHead({
  title: metaTitle,
  meta: [
    { property: "og:title", content: metaTitle },
    { property: "og:type", content: "website" },
    { property: "og:description", content: metaTitle },
  ],
});

metaTitle is generated dynamically.

There has been definitely some breaking changes since v. 1.0, because as soon as I downgrade to version 0.7.12 then everything works perfectly.

The way I test the SSR is using wget and then opening the downloaded web page in some editor.

Any help would be great. Thanks!

If you can make a reproduction repo I'll be happy to sort it out