website-astro/src/content/fragments/en/nuxt-graphql-static.md

3.2 KiB

title subtitle lang slug createdAt updatedAt excerpt tags type
Static website and GraphQL queries with Nuxt.js Graphql client is king. en nuxt-graphql-static 2022-06-08T14:24:06.000Z 2022-09-08T13:43:33.000Z When the most used gql module doesn't work…
nuxt.js
snippets

The problem

I encountered a nasty bug while using static generation with Nuxt and nuxt apollo client. I found the issue already reported on github.

It seems the module doesn't handle static generation correctly with nuxt generate.

I could find request to my local API url after the static generation. Moreover, it also seemed like <nuxt-link> navigation was broken.

The solution 🙌

Fortunately, there is another Nuxt module that handles GraphQL requests!

Nuxt graphql request to the rescue!

The conf

// nuxt.config.js
buildModules: [
  'nuxt-graphql-request',
],
graphql: {
  clients: {
    default: {
      endpoint: 'http://API_URL/graphql',
      options: {
        headers: {
          authorization: 'Bearer API_TOKEN',
        },
      },
    },
  },
},

The request

The best approach so far is to use asyncData in pages and fetch in components. Using fetch in pages does not work well at all with nuxt generate.

I also install the graphql-tag package (only in devDependencies) to be able to import directly .gql files.

Query example:

# homepage.gql
query {
	homepage {
		title
		subtitle
		hero {
			id
			alt
		}
	}
}

Inside a page

// index.vue
<script>
import homepageQuery from '~/graphql/queries/singles/homepage'

export default {
  async asyncData({ $graphql }) {
    const data = await $graphql.default.request(homepageQuery)
    return { data }
  },
}
</script>

Inside a component

It is safer to wait until fetch has received a response before displaying anything. You can use $fetchState to be sure (documentation).

// Header.vue
<template>
  <header v-if="!$fetchState.pending">
    
  </header>
</template>

<script>
import headerQuery from '~/graphql/queries/singles/header'

export default {
  data() {
    return {
      data: {},
    }
  },
  async fetch() {
    try {
      const data = await this.$graphql.default.request(headerQuery)
      this.data = data
    } catch (error) {
      console.error(JSON.stringify(error, undefined, 2))
    }
  },
}
</script>

Options

To pass options to the request, for example for a multilingual version with nuxt/i18n and/or a url parameter in a dynamic page:

// _slug.vue
<script>
import articleQuery from '~/graphql/queries/articles'

export default {
  async asyncData({ $graphql, app, params }) {
    const locale = app.i18n.localeProperties.iso
    const data = await $graphql.default.request(articleQuery, {
      code: locale,
      slug: params.slug,
    })
    return { data }
  },
}
</script>