Site statique et requêtes GraphQL avec Nuxt.js
Le client graphql est roi.
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,
permalink: params.slug,
})
return { data }
},
}
</script>