I am not able to create a sitemap for my Gatsy site.
The default setting of the plugin creates only one page even there is several pages:
<sitemap>
<loc>https://www.thesite.nl/sitemap/sitemap-0.xml</loc>
</sitemap>
If I try to override the default setting with:
query: `{
site {
siteMetadata {
siteUrl
}
}
allSitePage {
nodes {
path
}
}
}`,
serialize: ({ site, allSitePage }) =>
allSitePage.nodes
.filter(node => {
const path = node.path
console.log({ path })
// Filter out 404 pages
if (path.includes("404")) {
return false
}
// Filter out base pages that don't have a language directory
return supportedLanguages.includes(path.split("/")[1])
})
.map(node => {
return {
url: `${site.siteMetadata.siteUrl}${node.path}`,
changefreq: `weekly`,
priority: 0.7,
}
}),
I get TypeError: Cannot read property 'nodes' of undefined Problem is that with gatsby develop I can query the nodes like this and get the paths even it says undefined here.
I have Gatsby v3 and the only plugin I can think might affect could be "gatsby-plugin-intl": "^0.3.3",.
{
resolve: `gatsby-plugin-intl`,
options: {
// language JSON resource path
path: `${__dirname}/src/intl`,
// supported language
languages: [`nl`, `en`],
language: `nl`,
// language file path
defaultLanguage: `nl`,
// option to redirect to `/nl` when connecting `/`
redirect: false,
},
},
Any ideas?
Got it to build via custom options with gatsby build && gatsby serve after #FerranBuireu suggestion to change the query and now it looks like this but sitemap is still empty:
const siteUrl = process.env.URL || `https://www.thesite.nl`
{
resolve: "gatsby-plugin-sitemap",
options: {
query: `
{
allSitePage {
nodes {
path
}
}
}
`,
resolveSiteUrl: () => siteUrl,
resolvePages: ({ allSitePage: { nodes: allPages } }) => {
return allPages.map(page => {
return { ...page }
})
},
serialize: ({ path }) => {
return {
url: path,
}
},
},
},
I think your issue comes because you are not setting the resolveSiteUrl and, in this scenario, the siteUrl needs to be present. According to the docs:
siteMetadata: {
// If you didn't use the resolveSiteUrl option this needs to be set
siteUrl: `https://www.example.com`,
},
An ideal full configuration should be:
const siteUrl = process.env.URL || `https://fallback.net`
// In your gatsby-config.js
module.exports = {
plugins: [
{
resolve: "gatsby-plugin-sitemap",
options: {
query: `
{
allSitePage {
nodes {
path
}
}
allWpContentNode(filter: {nodeType: {in: ["Post", "Page"]}}) {
nodes {
... on WpPost {
uri
modifiedGmt
}
... on WpPage {
uri
modifiedGmt
}
}
}
}
`,
resolveSiteUrl: () => siteUrl,
resolvePages: ({
allSitePage: { nodes: allPages },
allWpContentNode: { nodes: allWpNodes },
}) => {
const wpNodeMap = allWpNodes.reduce((acc, node) => {
const { uri } = node
acc[uri] = node
return acc
}, {})
return allPages.map(page => {
return { ...page, ...wpNodeMap[page.path] }
})
},
serialize: ({ path, modifiedGmt }) => {
return {
url: path,
lastmod: modifiedGmt,
}
},
},
},
],
}
Tweak it and adapt it to fit your query.
I would do something like:
resolveSiteUrl: () => siteUrl,
resolvePages: ({
allSitePage: { nodes: allPages },
}) => {
const sitePageNodeMap = allSitePage.reduce((acc, node) => {
const { uri } = node
acc[uri] = node
return acc
}, {})
return allPages.map(page => {
return { ...page, ...sitePageNodeMap[page.path] }
})
},
serialize: ({ path, modifiedGmt }) => {
return {
url: path,
lastmod: modifiedGmt,
}
},
After mental and technical support from Ferran Buireu I managed to dig deeper.
In the public folder the sitemap was found under
sitemap/sitemap-0.xml giving the right path to all pages at thesite.nl/sitemap/sitemap-0.xml
Also notable that the <sitemapindex> is a valid element that points to the sitemap-0: https://www.sitemaps.org/protocol.html. Google search console still wants the /sitemap/sitemap-0.xml if submitted there.
So looks like the output of the pages was there most of the time. #idiot
Related
I have a hook..
export function useLazyProposalList() {
const [getQueueData, { loading, data, error, fetchMore }] = useLazyQuery(PROPOSAL_LIST, {
fetchPolicy: 'no-cache',
});
const proposalList = React.useMemo(() => {
if (!data) {
return null;
}
return transformProposals(data);
}, [data]);
return {
getQueueData,
fetchMore,
loading,
data: proposalList,
error,
};
}
In the component
const {
getQueueData,
data: queueData,
fetchMore: fetchMoreProposals,
// loadMore: loadMore,
} = useLazyProposalList();
If user clicks on fetch more button, I call: fetchMoreProposals .
await fetchMoreProposals({
variables: {
offset: visibleProposalList.length,
},
});
but this doesn't update my data. I read that we should use offsetLimitPagination, but my data from query is not array itself. It's like this: queue { id: '1', items:[] } and because of this, offsetLimitPagination doesn't work. So I tried merge
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
queue: {
keyArgs: false,
merge(existing, incoming) {
console.log(existing, incoming);
if (!incoming) return existing;
if (!existing) return incoming;
},
},
},
},
}
but in the console, it just prints refs instead of real data.
What could be the issue ?
I am trying to configure my Gatsby project like this starter https://github.com/gatsbyjs/gatsby-starter-blog
In my gatsby-node.js I have
const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
const blogPost = path.resolve(`./src/templates/blog-post.js`)
return graphql(
`
{
allMarkdownRemark(
sort: { fields: [frontmatter___date], order: DESC }
limit: 1000
) {
edges {
node {
fields {
slug
}
frontmatter {
title
}
}
}
}
}
`
).then(result => {
if (result.errors) {
throw result.errors
}
// Create blog posts pages.
const posts = result.data.allMarkdownRemark.edges
posts.forEach((post, index) => {
const previous = index === posts.length - 1 ? null : posts[index + 1].node
const next = index === 0 ? null : posts[index - 1].node
createPage({
path: `blog${post.node.fields.slug}`,
component: blogPost,
context: {
slug: post.node.fields.slug,
previous,
next,
},
})
})
return null
})
}
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `allMarkdownRemark`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
node,
value,
})
}
}
But I tried to run the dev server it output this error message
ERROR #85901 GRAPHQL
There was an error in your GraphQL query:
Cannot query field "fields" on type "MarkdownRemark".
File: gatsby-node.js:8:10
ERROR #11321 PLUGIN
"gatsby-node.js" threw an error while running the createPages lifecycle:
Cannot query field "fields" on type "MarkdownRemark".
GraphQL request:9:15
8 | node {
9 | fields {
| ^
10 | slug
But in fact what I had is allMarkdownRemark not MarkdownRemark. And I am totally copying what this starter is doing in its gatsby-node.js file
https://github.com/gatsbyjs/gatsby-starter-blog/blob/master/gatsby-node.js
Have no ideas how to fix it
My gatsby-config.js looks like this
"gatsby-plugin-page-transitions",
`gatsby-plugin-smoothscroll`,
`gatsby-plugin-netlify-cms`,
`gatsby-plugin-styled-components`,
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
`gatsby-plugin-offline`,
`gatsby-plugin-react-helmet`,
`gatsby-plugin-feed-mdx`,
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/content/blog`,
name: `blog`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/content/assets`,
name: `assets`,
},
},
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 590,
},
},
{
resolve: `gatsby-remark-responsive-iframe`,
options: {
wrapperStyle: `margin-bottom: 1.0725rem`,
},
},
`gatsby-remark-copy-linked-files`,
`gatsby-remark-smartypants`,
],
},
},
{
resolve: `gatsby-plugin-google-analytics`,
options: {
// edit below
// trackingId: `ADD YOUR TRACKING ID HERE`,
},
}
You are most likely seeing this issue because there are no markdown files found at any of the paths that gatsby-source-filesystem is pointing to in gatsby-config.js
According to nihgwu's comment on this issue:
the MarkdownRemark node type will only be created when there is a markdown node, or there will be no MarkdownRemark node type at all, so you can't query allMarkdownRemark
To solve your issue, make sure that there is as least one markdown file found in the ${__dirname}/content/blog folder.
If you do have markdown files in a different folder, make sure to add that location as another gatsby-source-filesystem entry in your gatsby-config.js.
In your gatsby-config.js file, make sure that gatsby-source-filesystem is able to detect a .md file in the directory where you put it. Then go to your gatsby-node.js file and change it to:
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
// Change the node internal type from 'allMarkdownRemark' to 'MarkdownRemark'
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
node,
value,
})
}
}
For more, check the docs on creating page programmatically.
In gatsby-node.js file, Change node.internal.type === allMarkdownRemark to MarkdownRemark in your oncreateNode function.
I was creating a gatsby plugin. On develop I don't get any errors or warning but I can't see my query in graphiql (or at http://localhost:8000/___graphql)
module.exports = {
siteMetadata: {
title: `Gatsby Default Starter`,
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`,
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
},
},
{
resolve: 'gatsby-source-custom',
options: {
workspaceId: 'spaceyfi-dummy',
schemaId: 'custom-development'
}
},
// this (optional) plugin enables Progressive Web App + Offline functionality
// To learn more, visit: https://gatsby.dev/offline
// `gatsby-plugin-offline`,
],
}
Where this is my plugin folder structure in root
Inside the folder, index.js is empty file
and getsby-node.js looks something like this
const selfSdk = require('selfSdk')
function createNodeContent (data, id, type) {
const nodeId = createNodeId(id)
const nodeContent = JSON.stringify(data)
const contentDigest = createContentDigest(data)
const nodeMeta = {
id: nodeId,
parent: null,
children: [],
internal: {
type: type, // used to generate the resulting GraphQL query name
content: nodeContent,
contentDigest
}
}
const node = Object.assign({}, data, nodeMeta)
return node
}
exports.sourceNodes = async ({ actions, createNodeId, createContentDigest }, {
workspaceId,
schemaId
}) => {
const { createNode, setPluginStatus } = actions
const workspace = selfSdk.getWorkspace(workspaceId)
console.log(workspaceId, schemaId)
// If there is schemaId but we don't have itemId, load all posts
try {
const itemsList = await workspace.read(schemaId)
const type = `getPosts`
itemsList.forEach(({data, id}) => {
createNode(createNodeContent(data, id, type))
})
} catch (error) {
console.error(`Error Fetching data`)
console.error(error)
}
setPluginStatus({
status: {
lastFetched: Date.now()
}
})
}
This my grphiql
Gatsby is going to look for a gatsby-node.js in the root of your plugin folder.
plugins/
– your-plugin/
-- gatsby-node.js
-- package.json
https://www.gatsbyjs.org/docs/files-gatsby-looks-for-in-a-plugin/
https://www.gatsbyjs.org/docs/creating-a-source-plugin/#what-does-the-code-look-like
This is why its not showing up in your GraphiQL. There is no node to be generated from your plugin, since you have a blank index.js so it seems like an module that doesn't export anything.
I know there are so many questions about this issue, but I honestly can't understand any of the answers.
What I understand is that everything happens at build time, and my code supports that.
What I want, is to access a folder that is the same name as the field "slug" in my data. I create the pages in the gatsby-node.js file.
Here is my code for that:
gatsby-node.js
exports.createPages = ({ actions }) => {
const data = require("./src/data/data.json")
const { createPage } = actions
data.forEach(data => {
createPage({
path: `/${data.slug}/`,
component: require.resolve('./src/templates/listing-template.js'),
context:{data},
})
})
}
I send the data in the context.
Now in my component, I want that data to be used in the query to get the specific folder for that page:
listing contains the data, and in filter: { relativeDirectory: { eq: I want to use it;
I have tried: ${listing.slug} but graphql won't allow it inside the eq.
How can I do this?
The query just takes all the files from the specified folder
const Listing2 = ({listing}) => {
const { casape } = useStaticQuery(
graphql`
query {
allFile(
sort: { fields: name, order: DESC }
filter: { relativeDirectory: { eq: "casape" } }
) {
edges {
node {
id
name
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid_withWebp_tracedSVG
}
}
}
}
}
}
`
)
I then use those returned images to create a gallery by the way.
What I tried:
const Listing2 = ({listing}) => {
const query = `
query {
allFile(
sort: { fields: name, order: DESC }
filter: { relativeDirectory: { eq: "casape" } }
) {
edges {
node {
id
name
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid_withWebp_tracedSVG
}
}
}
}
}
}
`
query.replace("casape", listing.slug)
const { allPhotos } = useStaticQuery(graphql`${query}`)
I also tried using the method
graphQl(query, parameters: {slug : listing.slug}}
and did
query Name($id = String!){
allFile(
sort: { fields: name, order: DESC }
filter: { relativeDirectory: { eq: $id
} }
But I get undefined.
When I click a profile (of an author) component, I can't figure out how it should render a scoped sub-component, listing the main entities of the app, so-called fabmoments (containers for 3D print information).
My current solution looks like this:
export default {
name: 'Multipe',
props: [
'author'
],
data () {
return {
// search: '',
localAuthor: '',
fabmoments: []
}
},
created () {
this.localAuthor = this.author
if (typeof localAuthor !== 'undefined') {
this.$http.get(`/users/${this.$route.params.id}/fabmoments`)
.then(request => this.buildFabmomentList(request.data))
.catch(() => { alert('Couldn\'t fetch faboments!') })
} else {
this.$http.get('/fabmoments')
.then(request => this.buildFabmomentList(request.data))
.catch(() => { alert('Couldn\'t fetch faboments!') })
}
},
methods: {
buildFabmomentList (data) {
this.fabmoments = data
}
},
components: {
// Box
}
}
This renders all in the profile, where it should render a list scoped to the current profile's author.
And it renders nothing in the home (without receiving the prop), where it should render all.
I am not much of star in JavaScript. What am I doing wrong?
UPDATE
This works as a solution, though not very elegant.
export default {
name: 'Multipe',
props: [
'author'
],
data () {
return {
fabmoments: []
}
},
created () {
if (this.author.id >= 0) {
this.$http.get(`/users/${this.$route.params.id}/fabmoments`)
.then(request => this.buildFabmomentList(request.data))
.catch(() => { alert('Couldn\'t fetch faboments!') })
} else {
this.$http.get('/fabmoments')
.then(request => this.buildFabmomentList(request.data))
.catch(() => { alert('Couldn\'t fetch faboments!') })
}
},
methods: {
buildFabmomentList (data) {
this.fabmoments = data
}
},
components: {
// Box
}
}
Not sure which part is wrong, but you may definitely debug your code to find out why fabmoments is empty array assuming there is no error occurred yet.
There are three parts to debug:
http response -- to check if data is properly returned
this -- to check if this pointer still points at the component
template -- to check if fabmoments are correctly bind to the element
At last, it would be better to separate your http request logics from your components.
Good luck!