Static website and GraphQL queries with Nuxt.js
Graphql client is king.
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,
permalink: params.slug,
})
return { data }
},
}
</script>