I'm building a website with GatsbyJS. I have markdown files in two different folders: /content/collections
and /content/posts
and I want Gatsby to create a page for each markdown file, with the respective template (collection.js and post.js).
So I wrote this in my gatsby-node.js file:
const path = require('path');
const { createFilePath } = require('gatsby-source-filesystem');
exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions;
if (node.internal.type === 'MarkdownRemark') {
const longSlug = createFilePath({ node, getNode, basePath: 'content' });
const slug = longSlug.split('/');
createNodeField({
node,
name: 'slug',
value: `/${slug[slug.length - 2]}/`,
});
}
};
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const result = await graphql(`
query {
allFile(filter: {relativeDirectory: {eq: "collections"}}) {
edges {
node {
childMarkdownRemark {
fields {
slug
}
}
}
}
}
}
`);
result.data.allFile.edges.forEach(({ node }) => {
createPage({
path: node.childMarkdownRemark.fields.slug,
ponent: path.resolve('./src/templates/collection.js'),
context: {
slug: node.childMarkdownRemark.fields.slug,
},
});
});
};
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const result = await graphql(`
query {
allFile(filter: {relativeDirectory: {eq: "posts"}}) {
edges {
node {
childMarkdownRemark {
fields {
slug
}
}
}
}
}
}
`);
result.data.allFile.edges.forEach(({ node }) => {
createPage({
path: node.childMarkdownRemark.fields.slug,
ponent: path.resolve('./src/templates/post.js'),
context: {
slug: node.childMarkdownRemark.fields.slug,
},
});
});
};
Thinking that it would work. It does work for the second type that I put in. (in this case it creates the posts, but not the collections. If I invert the order in which I call createPages it swaps, but it never creates all of them)
This is the error that I get in the console:
warning The GraphQL query in the non-page ponent "/Users/matteocarpi/Documents/Web/Ledue/src/templates/collection.js" will not be run.
Exported queries are only executed for Page ponents. It's possible you're
trying to create pages in your gatsby-node.js and that's failing for some
reason.
If the failing ponent(s) is a regular ponent and not intended to be a page
ponent, you generally want to use a <StaticQuery> ()
instead of exporting a page query.
If you're more experienced with GraphQL, you can also export GraphQL
fragments from ponents and pose the fragments in the Page ponent
query and pass data down into the child ponent —
The two templates are very similar:
import React from 'react';
import { graphql } from 'gatsby';
import PropTypes from 'prop-types';
const Post = ({data}) => {
return (
<div>
<h1>{data.postData.frontmatter.title}</h1>
</div>
);
};
export default Post;
export const query = graphql`
query PostData($slug: String!) {
postData: markdownRemark(fields: {slug: {eq: $slug}}) {
frontmatter {
title
}
}
}
`;
Post.propTypes = {
data: PropTypes.node,
};
import React from 'react';
import { graphql } from 'gatsby';
import PropTypes from 'prop-types';
const Collection = ({data}) => {
return (
<div>
<h1>{data.collectionData.frontmatter.title}</h1>
</div>
);
};
export default Collection;
export const query = graphql`
query CollectionData($slug: String!) {
collectionData: markdownRemark(fields: {slug: {eq: $slug}}) {
frontmatter {
title
}
}
}
`;
Collection.propTypes = {
data: PropTypes.node,
};
I tried refactoring all of the gatsby-node.js file following this answer but I end up in the same situation.
Where am I getting it wrong?
I'm building a website with GatsbyJS. I have markdown files in two different folders: /content/collections
and /content/posts
and I want Gatsby to create a page for each markdown file, with the respective template (collection.js and post.js).
So I wrote this in my gatsby-node.js file:
const path = require('path');
const { createFilePath } = require('gatsby-source-filesystem');
exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions;
if (node.internal.type === 'MarkdownRemark') {
const longSlug = createFilePath({ node, getNode, basePath: 'content' });
const slug = longSlug.split('/');
createNodeField({
node,
name: 'slug',
value: `/${slug[slug.length - 2]}/`,
});
}
};
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const result = await graphql(`
query {
allFile(filter: {relativeDirectory: {eq: "collections"}}) {
edges {
node {
childMarkdownRemark {
fields {
slug
}
}
}
}
}
}
`);
result.data.allFile.edges.forEach(({ node }) => {
createPage({
path: node.childMarkdownRemark.fields.slug,
ponent: path.resolve('./src/templates/collection.js'),
context: {
slug: node.childMarkdownRemark.fields.slug,
},
});
});
};
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const result = await graphql(`
query {
allFile(filter: {relativeDirectory: {eq: "posts"}}) {
edges {
node {
childMarkdownRemark {
fields {
slug
}
}
}
}
}
}
`);
result.data.allFile.edges.forEach(({ node }) => {
createPage({
path: node.childMarkdownRemark.fields.slug,
ponent: path.resolve('./src/templates/post.js'),
context: {
slug: node.childMarkdownRemark.fields.slug,
},
});
});
};
Thinking that it would work. It does work for the second type that I put in. (in this case it creates the posts, but not the collections. If I invert the order in which I call createPages it swaps, but it never creates all of them)
This is the error that I get in the console:
warning The GraphQL query in the non-page ponent "/Users/matteocarpi/Documents/Web/Ledue/src/templates/collection.js" will not be run.
Exported queries are only executed for Page ponents. It's possible you're
trying to create pages in your gatsby-node.js and that's failing for some
reason.
If the failing ponent(s) is a regular ponent and not intended to be a page
ponent, you generally want to use a <StaticQuery> (https://gatsbyjs/docs/static-query)
instead of exporting a page query.
If you're more experienced with GraphQL, you can also export GraphQL
fragments from ponents and pose the fragments in the Page ponent
query and pass data down into the child ponent — https://graphql/learn/queries/#fragments
The two templates are very similar:
import React from 'react';
import { graphql } from 'gatsby';
import PropTypes from 'prop-types';
const Post = ({data}) => {
return (
<div>
<h1>{data.postData.frontmatter.title}</h1>
</div>
);
};
export default Post;
export const query = graphql`
query PostData($slug: String!) {
postData: markdownRemark(fields: {slug: {eq: $slug}}) {
frontmatter {
title
}
}
}
`;
Post.propTypes = {
data: PropTypes.node,
};
import React from 'react';
import { graphql } from 'gatsby';
import PropTypes from 'prop-types';
const Collection = ({data}) => {
return (
<div>
<h1>{data.collectionData.frontmatter.title}</h1>
</div>
);
};
export default Collection;
export const query = graphql`
query CollectionData($slug: String!) {
collectionData: markdownRemark(fields: {slug: {eq: $slug}}) {
frontmatter {
title
}
}
}
`;
Collection.propTypes = {
data: PropTypes.node,
};
I tried refactoring all of the gatsby-node.js file following this answer but I end up in the same situation.
Where am I getting it wrong?
Share Improve this question asked Oct 29, 2020 at 15:21 Matteo CarpiMatteo Carpi 5928 silver badges25 bronze badges1 Answer
Reset to default 10The issue is that you're overriding your first function declaration with the second. A bit like this:
var a = "hello"
a = "world"
Instead you should do all of your querying and call createPage
for all pages you want to create in a single function, something like this:
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions;
const collections = graphql(`
query {
allFile(filter: {relativeDirectory: {eq: "collections"}}) {
edges {
node {
childMarkdownRemark {
fields {
slug
}
}
}
}
}
}
`).then(result => {
result.data.allFile.edges.forEach(({ node }) => {
createPage({
path: node.childMarkdownRemark.fields.slug,
ponent: path.resolve('./src/templates/collection.js'),
context: {
slug: node.childMarkdownRemark.fields.slug,
},
});
});
})
const posts = graphql(`
query {
allFile(filter: {relativeDirectory: {eq: "posts"}}) {
edges {
node {
childMarkdownRemark {
fields {
slug
}
}
}
}
}
}
`).then(result => {
result.data.allFile.edges.forEach(({ node }) => {
createPage({
path: node.childMarkdownRemark.fields.slug,
ponent: path.resolve('./src/templates/post.js'),
context: {
slug: node.childMarkdownRemark.fields.slug,
},
});
});
})
return Promise.all([collections, posts])
};