I have a Nuxt.js, statically generated site that has some dynamic pages. I'm using a GraphQL based headless CMS (DatoCMS) to provide the data for these pages, accessed using Apollo (@nuxt/apollo). I have it generating all the routes correctly but when I navigate to these pages from my site nav I'm receiving the following error 3 times:
TypeError: Cannot read property '_seoMetaTags' of undefined
at f.head (cf150f1920d36ab67139.js:1)
at wn.get (008dfc959ff6e6a713a0.js:2)
at wn.evaluate (008dfc959ff6e6a713a0.js:2)
at f.$metaInfo (008dfc959ff6e6a713a0.js:2)
at f.created (008dfc959ff6e6a713a0.js:2)
at Qt (008dfc959ff6e6a713a0.js:2)
at fn (008dfc959ff6e6a713a0.js:2)
at f.t._init (008dfc959ff6e6a713a0.js:2)
at new f (008dfc959ff6e6a713a0.js:2)
at 008dfc959ff6e6a713a0.js:2
This is coming from the head code in my page component so clearly something isn't being generated correctly. I can also see in the Chrome network tab that calls are being made to the GraphQL interface which also tells me the static generation isn't working correctly.
Here's the head() and apollo portions of my page component:
head() {
return {
title: this.blogPost._seoMetaTags.find(element => {
return element.tag === 'title';
}).content,
meta: [
{ hid: 'keywords', keywords: this.blogPost.keywords },
{ hid: 'description', description: this.blogPost._seoMetaTags.find(element => {
return element.tag === 'meta' && element.attributes.name === 'description';
}).attributes.content}
],
script: [
{ src: 'https://cdn.commento.io/js/commento.js', defer: true }
]
}
},
apollo: {
blogPost: {
query: gpl`
query BlogPost($slug: String!) {
blogPost(filter: { slug:{ eq: $slug }}) {
title
titleColor {
hex
}
slug
author
keywords
_seoMetaTags {
tag
attributes
content
}
_firstPublishedAt
banner {
id
url
title
}
content {
... on HeadingRecord {
_modelApiKey
heading
}
... on SubHeadingRecord {
_modelApiKey
subHeading
}
... on TextRecord {
_modelApiKey
content
}
... on CodeRecord {
_modelApiKey
codeBlock
}
... on ImageRecord {
_modelApiKey
image {
id
height
width
url
title
alt
}
}
... on VideoRecord {
_modelApiKey
video {
height
provider
providerUid
thumbnailUrl
title
url
width
}
}
}
}
}
`,
prefetch({ route }) {
return {
slug: route.params.slug
};
},
variables() {
return {
slug: this.$route.params.slug
};
}
And my nuxt.config.js if it helps:
const pkg = require('./package')
const webpack = require('webpack'); import fetch from 'node-fetch'; import { execute, makePromise } from 'apollo-link'; import { createHttpLink } from 'apollo-link-http'; import gql from 'graphql-tag';
module.exports = { mode: 'universal',
/*
** Headers of the page
*/
head: {
title: pkg.name,
htmlAttrs: {
lang: 'en'
},
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: pkg.description }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
{ rel: 'stylesheet', href: 'https://cdn.jsdelivr.net/gh/tonsky/[email protected]/distr/fira_code.css' }
]
},
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [
],
/*
** Plugins to load before mounting the App
*/
plugins: [
],
/*
** Nuxt.js modules
*/
modules: [
'@nuxtjs/style-resources',
'@nuxtjs/apollo',
'@nuxtjs/google-analytics'
],
/*
** @nuxtjs/google-analytics settings
*/
googleAnalytics: {
id: 'UA-136517294-1'
},
/*
** @nuxtjs/style-resources settings
*/
styleResources: {
scss: [
'./assets/css/*.scss'
]
},
/*
** Apollo setup for DatoCMS graphql queries
*/
apollo: {
includeNodeModules: true,
clientConfigs: {
default: '@/apollo/default.js'
}
},
/*
** Build configuration
*/
build: {
postcss: {
preset: {
features: {
customProperties: false
}
}
},
/*
** You can extend webpack config here
*/
extend(config, ctx) {
}
},
/*
** Generate configuration
*/
generate: {
routes: function(callback) {
// Get the list of posts
const uri = 'https://graphql.datocms.com';
const link = new createHttpLink({ uri: uri, fetch: fetch });
const operation = {
query: gql`
{
allBlogPosts {
id
slug
keywords
_seoMetaTags {
tag
attributes
content
}
}
}`,
context: {
headers: {
authorization: 'Bearer <my token>'
}
}
};
makePromise(execute(link, operation))
.then(data => {
// Build the routes from the posts
const postRoutes = data.data.allBlogPosts.map(item => {
return { route: `/blog/${item.slug}`, payload: { keywords: item.keywords, seoData: item._seoMetaTags }};
});
// Register the routes
callback(null, postRoutes);
})
.catch(error => console.log(`received error ${error}`));
}
}
}