Gatsby includes several Node APIs for building sites. In this lesson, we’ll use the createPages
API to dynamically build a page for each of our posts, by using the URL path in the frontmatter of each Markdown doc found via a GraphQL query.
Instructor: [00:00] We have our post title showing, but they're not clickable. Let's go ahead and make them links. To do that, we're going to import link from Gatsby. We can come down here to our frontmatter.title. We can surround this with link and our to prop will be frontmatter.path and save this.
[00:17] When this reloads, we can see that they're links now. When we click it, we get a 404 page. That's because we don't actually have a URL built for our post. In order for Gatsby to create the pages that we need for each blog post, we're going to create a file gatsby-node.js inside of the root of the directory.
[00:37] Inside of our source directory, we're going to create a templates directory and we will create a new file source/templates/blogpost.js. On the left hand side, I have gatsby-node.js, and on the right hand side, I have blogpost.js. Let's just knock out the blog post template first.
[01:03] We'll import React. We'll bring in GraphQL from Gatsby. Now, we'll just create a new constant template. We'll bring in props for now. Just to keep it simple, we'll do a return of just a div with blog post here.
[01:19] We'll export template by default and that will be good enough for now. There are several API's that Gatsby gives us access to. In order to create pages, we will use the aptly named create pages API. To get started, we'll create a new export function called createPages.
[01:35] We're going to destructure GraphQL for finding our files and actions which is where createPage lives. Now, we'll destructure createPage from our actions. Our createPages function will return a new promise due to the async nature of file creation.
[01:51] We'll do return new promise, which will have a resolve and a reject. In order to create the page, we're going to need access to our blog post template. We'll create a new variable for it. Since it's on the file system, we'll use path.resolve and send it to our source directory /templates/blogpost. We'll require path at the top of our file.
[02:15] Now we'll resolve the promise with a call to GraphQL, and we'll pass in our query for allMarkdownRemark.edges node frontmatter, and the path where we want our posts to live at.
[02:27] Now we'll add a then where we pass the result into a function, and result contains a data object with a shape that matches our query. We'll look at result.data.allMarkdownRemark.edges, and remember the edges are a path to the file system node.
[02:45] With this in mind, we're going to do a for each. Move this over to give us a little bit more room here. For each of our edges, we're going to extract the path from the node's frontmatter. We can destructure the node. We know that our path will be at node.frontmatter.path.
[03:05] Now, we can call the createPage action. The first parameter is a path for the page URL and will be the component to render, so in this case, the blog post template. The third parameter is the context object that will make its way into our blog post template component as a prop.
[03:22] We want our template to know what the path to our file is. We'll call it path slug, since path is a reserved keyword, and the value of path is what is supplied in our node frontmatter.
[03:33] After our call to createPage, we'll resolve that out of the promise. Since we have updated gatsby-node.js, we need to restart gatsby develop, so we run that. We get an error, "Cannot read property allMarkdownRemark of undefined."
[03:48] This would be on line 23. It's happening with result.data. There's something wrong with the query. Let's jump back over to our GraphiQL browser. It looks like the root query type. We need to add query.
[04:06] When we click into here, this is where allMarkdownRemark and stuff is. We just need to wrap this with query. Let's rerun gatsby develop, refresh the page, click, and we now have blog post here matching our blog post template.