• nuxt
  • graphql
  • jamstack

Site statique et requêtes GraphQL avec Nuxt.js

Le client graphql est roi.

Publié le : 5 août 2021

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>