nuxt-seomatic-meta-apollo
Version:
A fork of nuxt-seomatic-meta to get SEOMatic data into Nuxt, but with Apollo.
138 lines (119 loc) • 4.09 kB
JavaScript
const consola = require('consola')
import gql from 'graphql-tag'
export default ({ app }) => {
app.seomaticMeta = async function nuxtSeomaticMeta({ fullPath }, id = 1) {
const options = JSON.parse(`<%= JSON.stringify(options) %>`)
// Custom remapping of routes to other routes
// This is so you can grab seomatic data from another page
// Eg: Your nuxt homepage has a slug of '/' but you want data
// from a page in Craft with a slug of 'homepage'
let routeRemapPath
if (
typeof options.routeRemap === 'object' &&
options.routeRemap
) {
const foundRouteRemap = options.routeRemap.find(
({ path }) => path === fullPath,
)
routeRemapPath = foundRouteRemap && foundRouteRemap.getFrom
if (options.debug && routeRemapPath) {
consola.info(
`Getting metadata for '${fullPath}' from '${routeRemapPath}'`,
)
}
}
// Determine route name to use in graphql query
const routeName = routeRemapPath || fullPath
// Retrieve the seomatic graphql data via Apollo
if (app.apolloProvider === undefined) {
return consola.error(`SeomaticMeta plugin: Apollo not found, add it to your module array like this:\n\nmodules: ['nuxt-seomatic-meta-apollo', '@nuxtjs/apollo'],`)
}
// Uses default client because app.$apollo doesn't exist
const result = await app.apolloProvider.defaultClient.query({
headers: {
...options.graphqlToken && {Authorization: `Bearer ${options.graphqlToken}`},
},
query: gql`
query ($uri: String, $siteId: Int){
seomatic(uri: $uri, siteId: $siteId, asArray: true) {
metaTitleContainer
metaTagContainer
metaScriptContainer
metaLinkContainer
metaJsonLdContainer
... on SeomaticType {
metaTitleContainer
metaJsonLdContainer
metaLinkContainer
metaScriptContainer
metaTagContainer
}
}
}
`,
variables: {
uri: routeName,
siteId: id,
},
})
if (!result) consola.error(new Error(`No data was returned from Craft`))
if (options.debug) consola.info('Received GraphQl result', result)
const data = result.data.seomatic
// Convert the graphql JSON data to an object so we can work with it
const {
metaTitleContainer: {
title: { title },
},
metaTagContainer,
metaLinkContainer,
metaScriptContainer,
metaJsonLdContainer,
} = Object.entries(data).reduce(
(acc, [key, value]) => {
if (key !== '__typename') {
acc[key] = JSON.parse(value)
return acc
}
return acc
},
{},
)
// if (options.debug) consola.info('metaTitleContainer.title', title)
// Flatten metaTagContainer values into string
const meta = metaTagContainer
? Object.values(metaTagContainer).reduce(
(flat, next) => flat.concat(next),
[],
)
: null
// Flatten metaLinkContainer values into string
const link = metaLinkContainer
? Object.values(metaLinkContainer).reduce(
(flat, next) => flat.concat(next),
[],
)
: null
// Convert script data to <script>..</script>
const metaScripts = metaScriptContainer
? Object.values(metaScriptContainer).map(({ script }) => ({
innerHTML: script,
}))
: []
// Convert JsonLd to <script type="application/ld+json">...</script>
const jsonLd = metaJsonLdContainer
? Object.entries(metaJsonLdContainer).map(value => ({
type: 'application/ld+json',
innerHTML: JSON.stringify(value),
}))
: []
// Combine processed script data
const script = [...metaScripts, ...jsonLd]
return {
...(title && { title }),
...(meta && { meta }),
...(link && { link }),
script,
__dangerouslyDisableSanitizers: ['script'],
}
}
}