Reputation: 339
When building my Gatsby website I get the below error. I've tried to delete and reinstall npm, update the plugins, deleting (Gatsby) cache, playing around with the siteUrl and all kinds of settings in the Gatsby config. But I can't seem to get rid of the error. The development environment works fine.
github: https://github.com/bartfluitsma/gatsby-bart-fluitsma
**Error console log**
ERROR #11321 PLUGIN
"gatsby-plugin-sitemap" threw an error while running the onPostBuild lifecycle:
`siteUrl` does not exist on `siteMetadata` in the data returned from the query.
Add this to your `siteMetadata` object inside gatsby-config.js or add this to your custom query or provide a custom `resolveSiteUrl` function.
https://www.gatsbyjs.com/plugins/gatsby-plugin-sitemap/#api-reference
47 | errors = _yield$graphql.errors;
48 | _context.next = 9;
> 49 | return Promise.resolve(resolveSiteUrl(queryRecords)).catch(function (err) {
| ^
50 | return reporter.panic(_internals.REPORTER_PREFIX + " Error resolving Site URL", err);
51 | });
52 |
File: node_modules\gatsby-plugin-sitemap\gatsby-node.js:49:36
Error: `siteUrl` does not exist on `siteMetadata` in the data returned from the query.
Add this to your `siteMetadata` object inside gatsby-config.js or add this to your custom query or provide a custom `resolveSiteUrl` function.
https://www.gatsbyjs.com/plugins/gatsby-plugin-sitemap/#api-reference
- internals.js:62 resolveSiteUrl
[gatsby-bart-fluitsma]/[gatsby-plugin-sitemap]/internals.js:62:11
- gatsby-node.js:49 _callee$
[gatsby-bart-fluitsma]/[gatsby-plugin-sitemap]/gatsby-node.js:49:36
not finished onPostBuild - 0.480s
Gatsby-config.js
module.exports = {
siteMetadata: {
title: `Bart Fluitsma`,
description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
author: `@gatsbyjs`,
siteUrl: `http://bartfluitsma.com`,
},
plugins: [
`gatsby-plugin-react-helmet`,
`gatsby-plugin-image`,
'gatsby-plugin-postcss',
{
resolve: `gatsby-plugin-google-fonts-with-attributes`,
options: {
fonts: [
`montserrat\:300,400,400i,600,900`,
],
display: 'swap',
attributes: {
rel: "stylesheet preload prefetch",
},
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
}, {
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/src/locales`,
name: `locale`
}
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `Web development | Bart Fluitsma`,
short_name: `Bart develops`,
start_url: `/`,
background_color: `#663399`,
// This will impact how browsers show your PWA/website
// https://css-tricks.com/meta-theme-color-and-trickery/
// theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/images/logo-bart-fluitsma-web-design.svg`, // This path is relative to the root of the site.
},
},
{
resolve: `gatsby-plugin-react-i18next`,
options: {
localeJsonSourceName: `locale`, // name given to `gatsby-source-filesystem` plugin.
languages: [`en`, `nl`],
defaultLanguage: `en`,
// if you are using Helmet, you must include siteUrl, and make sure you add http:https
siteUrl: `https://bartfluitsma.com`,
// you can pass any i18next options
i18nextOptions: {
interpolation: {
escapeValue: false // not needed for react as it escapes by default
},
keySeparator: false,
nsSeparator: false
},
pages: [
{
matchPath: '/:lang?/blog/:uid',
getLanguageFromPath: true
},
]
}
},
// this (optional) plugin enables Progressive Web App + Offline functionality
// To learn more, visit: https://gatsby.dev/offline
// `gatsby-plugin-offline`,
{
resolve: 'gatsby-plugin-sitemap',
options: {
excludes: ['/**/404', '/**/404.html'],
query: `
{
site {
siteMetadata {
siteUrl
}
}
allSitePage(filter: {context: {i18n: {routed: {eq: false}}}}) {
edges {
node {
context {
i18n {
defaultLanguage
languages
originalPath
}
}
path
}
}
}
}
`,
serialize: ({ site, allSitePage }) => {
return allSitePage.edges.map((edge) => {
const { languages, originalPath, defaultLanguage } = edge.node.context.i18n;
const { siteUrl } = site.siteMetadata;
const url = siteUrl + originalPath;
const links = [
{ lang: defaultLanguage, url },
{ lang: 'x-default', url }
];
languages.forEach((lang) => {
if (lang === defaultLanguage) return;
links.push({ lang, url: `${siteUrl}/${lang}${originalPath}` });
});
return {
url,
changefreq: 'daily',
priority: originalPath === '/' ? 1.0 : 0.7,
links
};
});
}
}
},
],
}
Upvotes: 5
Views: 1943
Reputation: 29
I'm customizing the code for generating a multilingual sitemap as follows. In the actual production code, each language in the 'languages' variable is retrieved from the i18n configuration settings.
import type { GatsbyConfig } from 'gatsby'
const languages = ['en', 'fr', 'ja']
const config: GatsbyConfig = {
plugins: [
'gatsby-plugin-pnpm',
'gatsby-plugin-postcss',
{
resolve: `gatsby-plugin-sitemap`,
options: {
excludes: ['/**/404', '/**/404.html'],
serialize: ({ path }) => {
// Get the page path without the language code.
const pagepath = path.replace(/\/.*?\//, '/')
// Generate XML links for each language.
const xmlLinks = languages.map((lang: string) => ({
rel: 'alternate',
hreflang: lang,
url: `/${lang}${pagepath}`
}))
xmlLinks.push({
rel: 'alternate',
hreflang: 'x-default',
url: `${pagepath}`
})
let entry = {
url: path,
changefreq: 'daily',
links: xmlLinks
}
return entry
}
}
}
]
}
The generated XML looks as below.
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
<url>
<loc>https://sample.com/</loc>
<changefreq>daily</changefreq>
<xhtml:link rel="alternate" hreflang="en" href="https://sample.com/en/" />
<xhtml:link rel="alternate" hreflang="ja" href="https://sample.com/ja/" />
<xhtml:link rel="alternate" hreflang="x-default" href="https://sample.com/" />
</url>
<url>
<loc>https://sample.com/en/</loc>
<changefreq>daily</changefreq>
<xhtml:link rel="alternate" hreflang="en" href="https://sample.com/en/" />
<xhtml:link rel="alternate" hreflang="ja" href="https://sample.com/ja/" />
<xhtml:link rel="alternate" hreflang="x-default" href="https://sample.com/" />
</url>
<url>
<loc>https://sample.com/ja/</loc>
<changefreq>daily</changefreq>
<xhtml:link rel="alternate" hreflang="en" href="https://sample.com/en/" />
<xhtml:link rel="alternate" hreflang="ja" href="https://sample.com/ja/" />
<xhtml:link rel="alternate" hreflang="x-default" href="https://sample.com/" />
</url>
</urlset>
Versions: Node: v19.4.0
"gatsby": "v19.4.0",
"gatsby-plugin-sitemap": "6.11.0"
Upvotes: 0
Reputation: 81
This worked for me without the need to create new types:
{
resolve: "gatsby-plugin-sitemap",
options: {
excludes: ["/**/404", "/**/404.html"],
resolveSiteUrl: () => siteUrl,
query: `
{
allSitePage {
edges {
node {
pageContext
}
}
}
}
`,
resolvePages: ({ allSitePage: { edges } }) => {
return edges
.filter(
({ node }) => !["/404/", "/404.html"].includes(node.pageContext.i18n.originalPath)
)
.map(({ node: { pageContext } }) => {
const { languages, originalPath, path, defaultLanguage } = pageContext.i18n;
const baseUrl = siteUrl + originalPath;
const links = [{ lang: "x-default", url: baseUrl }];
languages.forEach((lang) => {
const isDefaultLang = lang === defaultLanguage;
const isDefaultPath = path === originalPath;
const isLangSubDir = path.includes(`${lang}/`);
if (isDefaultLang && isDefaultPath) return;
if (!isDefaultLang && isLangSubDir) return;
links.push({
lang,
url: isDefaultLang ? baseUrl : `${siteUrl}/${lang}${originalPath}`,
});
});
return {
path,
url: path === "/" ? siteUrl : `${siteUrl}/${path}`,
changefreq: "daily",
priority: originalPath === "/" ? 1.0 : 0.7,
links,
};
});
},
serialize: (page) => page,
},
}
Versions: Node: 18.13.0
"gatsby": "^5.3.3",
"gatsby-plugin-react-i18next": "^3.0.1",
"gatsby-plugin-sitemap": "^6.5.0",
Upvotes: 2
Reputation: 2539
The answer by Ferran Buireu ultimately was not the solution for OP. I had experienced the same issue and this solution would have solved his issue hadn't he abandoned it. Check this GitHub thread.
Your siteUrl
issue just masks that the query was invalid, as the context
is not available in gatsby >= 4 anymore, as you found out after fixing the siteUrl
.
You may have used this query from the gatsby-plugin-react-i18next docs to support a sitemap.
In order to make it work, I found you have to 1. create the context yourself, and 2. adjust the queries
gatsby-node.js
(credit wilsonvolker)/**
* Workaround for missing sitePage.context:
* Used for generating sitemap with `gatsby-plugin-react-i18next` and `gatsby-plugin-sitemap` plugins
* https://www.gatsbyjs.com/docs/reference/release-notes/migrating-from-v3-to-v4/#field-sitepagecontext-is-no-longer-available-in-graphql-queries
*/
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions
createTypes(`
type SitePage implements Node {
context: SitePageContext
}
type SitePageContext {
i18n: i18nContext
}
type i18nContext {
language: String,
languages: [String],
defaultLanguage: String,
originalPath: String
routed: Boolean
}
`)
}
serialize
function proposed in the i18next doesn't work as-is anymore since it apparently receives a single node, not the full graphql response. So, a few changes in gatsby-config.js
to make it work again (this assumes you have a global siteUrl
variable available):query: `
{
site {
siteMetadata {
siteUrl
}
}
allSitePage(filter: {context: {i18n: {routed: {eq: false}}}}) {
nodes {
context {
i18n {
defaultLanguage
languages
originalPath
}
}
path
}
}
}
`,
serialize: (node) => {
const { languages, originalPath, defaultLanguage } = node.context.i18n
const url = siteUrl + originalPath
const links = [
{ lang: defaultLanguage, url },
{ lang: 'x-default', url },
]
languages.forEach((lang) => {
if (lang === defaultLanguage) return
links.push({ lang, url: `${siteUrl}/${lang}${originalPath}` })
})
return {
url,
changefreq: 'daily',
priority: originalPath === '/' ? 1.0 : 0.7,
links,
}
},
Upvotes: 3
Reputation: 29315
The error is thrown by gatsby-plugin-sitemap
. Try adding the resolveSiteUrl
method in your configuration like:
const siteUrl = process.env.URL || `https://fallback.net`
resolveSiteUrl: () => siteUrl,
Applied to your code:
const siteUrl = process.env.URL || `https://fallback.net`
module.exports = {
plugins: [
{
resolve: "gatsby-plugin-sitemap",
options: {
excludes: ["/**/404", "/**/404.html"],
query: `
{
site {
siteMetadata {
siteUrl
}
}
allSitePage(filter: {context: {i18n: {routed: {eq: false}}}}) {
edges {
node {
context {
i18n {
defaultLanguage
languages
originalPath
}
}
path
}
}
}
}
`,
resolveSiteUrl: () => siteUrl,
serialize: ({ site, allSitePage }) => {
return allSitePage.edges.map((edge) => {
const { languages, originalPath, defaultLanguage } =
edge.node.context.i18n;
const { siteUrl } = site.siteMetadata;
const url = siteUrl + originalPath;
const links = [
{ lang: defaultLanguage, url },
{ lang: "x-default", url },
];
languages.forEach((lang) => {
if (lang === defaultLanguage) return;
links.push({ lang, url: `${siteUrl}/${lang}${originalPath}` });
});
return {
url,
changefreq: "daily",
priority: originalPath === "/" ? 1.0 : 0.7,
links,
};
});
},
},
},
],
};
Change the siteUrl
and the fallback URL accordingly if you are not setting it in your environment file
Upvotes: 3