So I'm writing a small app and I came across an issue that I haven't been able to solve. First, I have this here: https://www.gatsbyjs.org/tutorial/authentication-tutorial/ which allows me to use this:
// Implement the Gatsby API “onCreatePage”. This is
// called after every page is created.
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions
// page.matchPath is a special key that's used for matching pages
// only on the client.
if (page.path.match(/^\/app/)) {
page.matchPath = "/app/*"
// Update the page.
createPage(page)
}
}
Then I'm using a graphql query to query static data (blog posts). The issue is that I'm unable to do both, for some reason.
When I run the following, I'm greeted with an error of 'Cannot read property path of undefined.'
exports.createPages = async ({ page, actions, graphql, reporter }) => {
const { createPage } = await actions
if (page.path.match(/^\/anime/)) {
page.matchPath = "/anime/*"
createPage(page)
}
const result = await graphql(`
{
allMarkdownRemark {
edges {
node {
html
id
frontmatter {
path
title
date
author
}
}
}
}
}
`)
const blogs = result.data.allMarkdownRemark.edges
blogs.forEach(({ node }) => {
const title = node.frontmatter.path
actions.createPage({
path: `${title}`,
component: require.resolve("./src/templates/newsletter.template.js"),
})
})
}
// exports.createPages = async ({ actions, graphql, reporter }) => {
// }
Now, when I run the following code, I do not get any errors. However, when I do it this way and go to the expected route of my blog(s) I'm prompted with post is null.
So my question is this: How can I use createPages/onCreatePage with both of these and have both work?
(Bonus question, but ties into the above)
When I change the route(s) of my blog post(s) in the frontmatter to /title-of-post/ ( being the starting route, in this case, it's newsletter) I no longer have post is null as pointed out above. But, I want my blog posts to have the route name in front of them. So my question is this: How do I make all of this work?
https://github.com/Joey-Robinson/quick-anime
Is the repo name. Note: I've already tried making a folder in pages with the name of newsletter, but that didn't do anything.
Edit: Formatting.
Edit Two: Formatting.
exports.createPages = async ({ page, actions, graphql, reporter }) => { const { createPage } = await actions if (page.path.match(/^\/anime/)) { page.matchPath = "/anime/*" createPage(page) }
You can't put this in createPages, because the page property in the first line is not a valid property for that API endpoint. That's why you're getting the Cannot read property 'path' of undefined error.
onCreatePage() is triggered by the createPage() action, so the page property in it represents the page that was just created. If you keep that whole section in onCreatePage(), and keep the page generation using GraphQL in createPages(), you should be okay.
Now, when I run the following code, I do not get any errors. However, when I do it this way and go to the expected route of my blog(s) I'm prompted with post is null.
Should there have been more code following this paragraph, or was it referring to your repo? I ask because I'm not sure where you were getting the post is null error; I wasn't able to reproduce that.
When I change the route(s) of my blog post(s) in the frontmatter to _/title-of-post/ (_ being the starting route, in this case, it's newsletter) I no longer have
post is nullas pointed out above. But, I want my blog posts to have the route name in front of them. So my question is this: How do I make all of this work?
I was able to make that happen by changing the path frontmatter field in the file 2011-06-23-the-greatness-of-cowboy-bebop/the-greatness-of-cowboy-bebop.md to equal /newsletter/the-greatness-of-cowboy-bebop/.
---
path: "/newsletter/the-greatness-of-cowboy-bebop/"
title: "The Greatness Of Cowboy Bebop"
date: "2011-06-23"
author: "Joey Robinson"
featuredImage: ../../static/cbi.jpg
---
Because of this section, the path frontmatter field becomes the absolute URL for the page:
blogs.forEach(({ node }) => { const title = node.frontmatter.path actions.createPage({ path: `${title}`, component: require.resolve("./src/templates/newsletter.template.js"), }) })
You could change
path: `${title}`
to equal whatever you wanted. Maybe if you wanted to combine a category prefix and a slug to make the route:
blogs.forEach(({ node }) => { const slug = node.frontmatter.slug const cat = node.frontmatter.category actions.createPage({ path: `/${cat}/${slug}`, component: require.resolve("./src/templates/newsletter.template.js"), }) })
Just kind of a side note: I probably wouldn't keep my markdown files in the pages directory, since normally those files are for Gatsby to pick up and turn into pages automatically, and their routes would reflect the folder structure there. In this context, it might make more sense to keep the .md files in a different location, and point a gatsby-source-filesystem instance there. Since this is apart from the default page rendering process, it should help make their usage a bit clearer.
So for the onCreatePage() and the createPages() I should just leave separated to achieve what I'm after?
For the pathing on the blog pages: I had usually put then in the pages directory, but after reading your comment and looking at other peoples repos, it seems that that's not the best way, so I'll change that.
Edit: This is what I have currently: https://github.com/Joey-Robinson/quick-anime/tree/002f6b73c253c88866fe2a4ca37d2d0633fd50dd
So for the
onCreatePage()and thecreatePages()I should just leave separated to achieve what I'm after?
Yup, that's correct 🙂.
What's happening under the hood is Gatsby is using gatsby-plugin-page-creator to process your pages directory. As it collects the files, it calls the createPage() action, which will trigger your onCreatePage() event.
Edit: This is what I have currently: https://github.com/Joey-Robinson/quick-anime/tree/002f6b73c253c88866fe2a4ca37d2d0633fd50dd
Looks pretty good to me. One thing that will happen here is you will wind up with double slashes at the beginning and end, since your slug reads /newsletter/the-greatness-of-cowboy-bebop/. It shouldn't be a big deal, because your browser should just ignore double slashes.
My example was just to show one of the things you could do for organizing your posts/building your URLs. In my example, I would have made the .md file read:
slug: "the-greatness-of-cowboy-bebop"
category: "newsletter"
Then I can construct my URL from the simple values in the frontmatter. There's plenty of ways to achieve that kind of affect, and the way you are doing it should be fine.
@Joey-Robinson did that answer your questions?
Oh sorry, forgot to update. Absolutely! Everything works like a charm and as expected. Thank you so much.
Glad to hear it!
I'm closing this issue as answered, but if you have anymore questions, please feel free to come back and comment.
Most helpful comment
@Joey-Robinson did that answer your questions?