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

3.6 KiB

title subtitle lang slug createdAt updatedAt excerpt tags type
Site statique et requêtes GraphQL avec Nuxt.js Le client graphql est roi. fr nuxt-graphql-static 2022-06-08T14:24:06.000Z 2022-09-08T13:43:33.000Z Quand le module gql le plus utilisé ne fonctionne pas…
nuxt.js
fragments

Le problème

Je me suis heurté à un villain bug en utilisant Nuxt en mode génération statique complète et le client nuxt apollo. Après quelques recherches, voici le bug constaté par quelqu'un d'autre sur github.

Il semblerait que le module en l'état ne gère pas correctement la génération statique avec nuxt generate.

Je trouvais toujours des appels à mon API locale après la génération statique et la navigation depuis les <nuxt-link> ne fonctionnait pas.

La solution 🙌

Heureusement, il existe un autre module Nuxt pour gérer les requêtes GraphQL !

Nuxt graphql request à la rescousse !

La conf

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

La requête

La meilleure méthode à ce jour est d'utiliser asyncData dans les pages et fetch dans les composants. Utiliser fetch dans les pages ne fonctionne pas bien du tout avec nuxt generate.

J'installe également le paquet graphql-tag (uniquement en devDependencies) afin de pouvoir importer directement des fichiers .gql

Exemple de fichier :

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

Dans une 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>

Dans un composant

Il est plus prudent d'attendre que fetch ait reçu une réponse avant d'afficher quoi que ce soit. On peut utiliser $fetchState afin d'être tranquille (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>

Les options

Pour passer des options à la requête, par exemple pour une version multilingue avec nuxt/i18n et/ou un paramètre d'url dans le cadre d'une page dynamique :

// _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>