nuxt / nuxt

The Intuitive Vue Framework.
https://nuxt.com
MIT License
54.07k stars 4.94k forks source link

Data fetching inside a composable breaks useHead #28639

Closed TheDutchCoder closed 6 days ago

TheDutchCoder commented 3 weeks ago

Environment


Reproduction

https://stackblitz.com/edit/github-pp3ujf?file=nuxt.config.ts,pages%2Fpage1.vue,pages%2Fpage2.vue,app.vue,pages%2Findex.vue

Describe the bug

In this case we're using useJsonld, but this goes for other composables using useHead as well (afact). Whenever data is fetched in a composable and useHead is being used consuming that data, things start to fall apart.

In this specific case useJsonld doesn't add any jsonld data to the page (server-side). This module really only uses useHead under the hood though, it's not very special.

Additional context

No response

Logs

No response

stackblitz[bot] commented 3 weeks ago

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

danielroe commented 3 weeks ago

You should use nuxtApp.runWithContext if you are calling a composable that needs the Nuxt instance after an await within your own composable.

More details: https://nuxt.com/docs/api/composables/use-nuxt-app#runwithcontext.

TheDutchCoder commented 3 weeks ago

@danielroe

I've updated the Stackblitz to show you that this doesn't work either. Can you please reopen?

I also want to add that this worked before btw, so there's likely been an update to unhead or Nuxt itself that reintroduced the issue (at least that's my initial thought).

danielroe commented 3 weeks ago

You have to call useNuxtApp before the await - that's the issue.

TheDutchCoder commented 3 weeks ago

That still doesn't work. Neither when I call if before the await in the composable, nor when I call it on the root level.

Both of these approaches don't work:

async function useMyThing() {
  const app = useNuxtApp();

  const { data } = await useFetch('https://cat-fact.herokuapp.com/facts');

  app.runWithContext(() => {
    useJsonld(() => ({
      '@context': 'https://schema.org',
      '@type': 'cat',
    }));
  });

  return {
    data,
  };
}

const { data } = await useMyThing();
const app = useNuxtApp();

async function useMyThing() {
  const { data } = await useFetch('https://cat-fact.herokuapp.com/facts');

  app.runWithContext(() => {
    useJsonld(() => ({
      '@context': 'https://schema.org',
      '@type': 'cat',
    }));
  });

  return {
    data,
  };
}

const { data } = await useMyThing();
danielroe commented 3 weeks ago

Oh, I would definitely consider that a bug then...

danielroe commented 3 weeks ago

cc: @harlan-zw

harlan-zw commented 6 days ago

@TheDutchCoder You're not using the module correctly, this would be the correct usage as far as I can tell. I'd make an issue on the module if you're still having issues.

<script setup>
const app = useNuxtApp();
const jsonLd = ref();
useJsonld(() => jsonLd.value);

async function useMyThing() {
  const { data } = await useFetch('https://cat-fact.herokuapp.com/facts');

  jsonLd.value = {
    '@context': 'https://schema.org',
    '@type': 'cat',
  };

  return {
    data,
  };
}

const { data } = await useMyThing();
</script>

Alternatively, I'd recommend nuxt-schema-org if you want something that wraps useHead more directly.