Production-Grade Next.js Dynamic Content & Dynamic Routes
Transcript from the "Dynamic Content & Dynamic Routes" Lesson
>> So the next one we're gonna talk about is dynamic routes and content. So previously we talked about static routes with content with static pages. So now we're gonna talk about dynamic content on a dynamic route that generates a static page. So again, so many terms, but I think it's important to really understand how these work.
[00:00:22] Because depending on how you build your app and the type of page it is, where you're getting the data from, it's going to determine a user experience really. But the beautiful thing about it, is that next.js allows you to basically opt in and opt out and pretty much do whatever you want, whenever you want.
[00:00:41] It has so many options and you're gonna see. And I'll highlight them here in the syllabus, cuz even I'm just like, this is crazy and this is insane that you can do this. So, yeah, enough about that. Let's hop right in. So, basically, we're going to create a blog, right, so we want our blog to be able to pull from our CMS.
[00:01:02] And we want it to be able to handle new posts that come in and stuff like that. So that's what we're going to do. So, just a little recap on the app and how things work. If we go look at our app here, and we go look at the blog, we have two pages in here.
[00:01:21] So this index page, this is basically the page when you go to someone's blog, and it shows you all the blog entries with their summaries and you click on one, okay, that's what this page is. This is just a index for all your blogs, some people will paginate this if they have a lot.
[00:01:36] We're not doing all that, we're just gonna list all the blogs in our summaries here. And then when you click on the blog, it's gonna take you to this page, which is an individual post. And that's where you'll actually be able to see the full posts and all that stuff.
[00:01:49] So we're gonna make both of these actually work. So, first thing we're going to do is head over to the index page. And we need to basically do the same thing we did for the landing page index, because right now it's just getting posts from default props, which is empty, it's just a empty array.
[00:02:11] So we need to actually get the posts from our CMS but also we have posts from our file system. I obviously wouldn't recommend doing this in real life, having some content, some blog posts coming from your file system, and then also having some content coming from a CMS.
[00:02:29] I don't know why you would do that. But yeah, I don't recommend doing that. But we're doing it so I can show you the power of how you can use different sources inside of your static props and how you can mix things together, and how next.js just doesn't care.
[00:02:44] So that's what we're going to do. So we're going to pull from our CMS, which if we go look at that, which is just content.js, where's that, there we go content.ts, I'm sorry. You can see we have seen some published blog posts down here, put in draft from one to two as well.
[00:02:59] So we're just going to pull from both of these. So the first thing we wanna do is, basically, we're gonna create our git static props inside the index page. And there, the index page is basically just gonna be responsible for just getting basically those blog posts, getting your frontmatter from those NDX files, and we just want to be able to get the title in the summary, and that's it.
[00:03:21] Cuz that's all we're going to show in that preview, we don't really care about the full post on that page. So we'll work on that. So the first thing we're going to do is we're going to actually add the git static props on the index page, so let's do that.
[00:03:36] So I'm gonna go here to the index page of blog. And I'm going to go down here, and I'm going to say export const, or not const, let's do function, export function getStaticProps like that, okay? And then what I wanna do here, is like I said, we have some inside of the CMS, and then we have some inside of the file system.
[00:04:02] So let's do the CMS first. I'm already importing it up top. I imported mine as posts from CMS, so we don't confuse the two. So I'm gonna do that. So I'm gonna get the post from the CMS here, it says return some props. And it looks like they need to be in an array called post.
[00:04:19] So I'll just put post here. And then we need to actually go make these posts here. So, the first thing we need to do is if we look at the blog post, it doesn't matter if it's coming from the CMS or not, it's just in DX. So you can see there's some frontmatter here, and then there's some actual mark down, right?
[00:04:40] And if we go look at the ones on the filesystem, they're the same thing. We got some frontmatter and then some mark down, it's the same thing. So technically, they should work the same way. So that's how we're gonna handle it. So the first thing we wanna do is we want to transform the ones from the CMS to be able to get the actual data from the frontmatter, we wanna parse that out.
[00:05:03] So what we'll do is we'll go ahead and we'll say, these will be posts from, well, I guess it's already there, I'll just call it CMS posts. And this is gonna eqauls postsFromCMS.map, we're gonna map over those. We're gonna get a post. And then what we're gonna do here is we're just going to return, I have a package up here called matter.
[00:05:27] So matter takes in a markdown string, and it will return the content and then the frontmatter in a JSON object. So that's what we'll use. So I'm going to return matter, like this. And actually, I don't really want the constant right here, okay. No, I gotta hit escape, no, x, there we go.
[00:05:50] Okay, I almost hit escape. [LAUGH] So I need to just return the matter here. So I'll just say data, and then matter like this. And then what I can do is I can pass in the posts, or I think this is postCMS.published. Is that published? Here we go, yeah, so we look at the publish ones.
[00:06:15] Then I'm gonna get the post type scripts written out, but it's all right. And then I want to pass in the post here, this is going to give us a data, like that. Yeah, what's the return value obviously, and then I'm just gonna return the data. So this is gonna return a JSON object for this, it's basically alternatives to an object.
[00:06:36] So we'll have a title, a publishedOn, an author summary, slug, same thing for the content. It's the same thing, title, summary, slug, all that stuff. So we got that for the CMS post. We can do the same thing for the filesystem post, all right? So the first thing we need to do is well, how do you read the filesystem and node, right?
[00:06:58] Anyone know how to do that, right? You use the filesystem packages built into node, but wait, we're in a react component. How are we importing? If you try to import this right now, and create react app, tell me what happens, [LAUGH] right? It's not gonna be good, right?
[00:07:15] We're actually importing node stuff inside of a client's react file, and I think that part can be confusing. The reason this works and the reason that's magical is because next.js actually removes all the server side code that's used and the server side functions. They don't actually get bundled to the browser.
[00:07:38] They get executed on the server, but they don't get bundled to the browser. So we can import node only code in here, server side code, and be rest assured that it's still gonna work in the browser, right? You can't use a filesystem in the browser, you can't use path in a browser.
[00:07:56] But we can use it in a page index.js as long as it's going to be used inside of a git static props. So that's what we're going to do. So let's get the directory so we'll say post directory is going to equal fs.read, lets do readerSync I guess.
[00:08:14] And we'll say process.cwd, because we're in node, we can do process, all right? So we'll do that, and then we'll pass in posts, because I'm pretty sure that's where these are, all right? So we got post, that's the directory. So then what we want to do, what was this thing.
[00:08:36] Okay, I think I just need to do, let's make a path first. So let's make a posts path and we'll do a path.join or actually, maybe a path.resolve. Let's do path.join. We'll do path.join and we'll say process.cwd like this. And then we'll say posts like that. And then what we can do is we can just pass this in here.
[00:09:07] Like that, posts path. There we go. So we'll read this, we'll get the directory. And then what we want to do is we want to loop over each thing here, right? We want to basically go and get every single file inside of the directory, so like this. So like what I have here, if you're following along here, you can see we're just gonna loop over the file names, right?
[00:09:35] Because this is gonna give us back an array of file names. So we just wanna loop over that. So that's what we're gonna do. Let me go back here. So we're gonna say, actually, I'll probably just keep it consistent, I'll call this filenames. And then I'll just say this will be filePosts, I guess.
[00:09:54] I will say filenames.map, we'll get the name here. And then we actually need to read the file, so we'll say file = fs.readFile. And then what we can do is we can pass in the name like that. So we get the name, and then we can do etf, e for the encoding.
[00:10:20] And we'll do readFileSync actually. So then we'll do readFileSync here, why is this thing freaking out? I guess it wants me to do return. So then we'll get the file here. And now that we have the file, we're pretty much in the same spot where we were up here, where we have a string, we can pass it to matter.
[00:10:35] That'll give us back some data, and so we'll do that. So we'll get the data here, oops. It came back up. There we go, get some data here. And, wait, why can't I type now? There we go, okay. And we'll say matter and we'll pass in the file that'll give us the data and it will just return the data, just like that.
[00:11:07] Everybody following me so far? So we got the post from our CMS, we converted its frontmatter to objects. We got the post from the filesystem, we converted those to objects. So now we have two arrays of similar looking things. And we have this posting that's supposed to be here, so then we'll just come down here and we'll say const posts equals some array, I'm gonna spread over my cmsPosts and then I'm gonna spread over my file post, filePosts, there we go.
[00:11:42] So now I got all those posts. And then I can just pass them down like that, right, I need to add the actual full path. So let's get the fullPath of path.join(process.cwd) and then we want to get the, what was it, post? Oops. And then we want to get the name, like that.
[00:12:12] And then we can put that in there, fullPath. I put post, it posts, there we go, all right. I get it wrong all the time. Okay, and then now this one is saying, basically, this is freaking out. Let me see, post props must be returned as a plain object.
[00:12:33] Let's see, yeah, I guess I'll just put an array here, obviously, that needs to be like posts, like that. So let's do that. And then, boom, now we got some posts. So you can see here, if we go look at the content, I can tell you cuz I built this, these two are gonna be from the CMS.
[00:12:51] And then these next three are actually from the filesystem. So, we can go confirm, if I go look at the CMS here, I have one that starts with, I'm looking at the published ones, it says we're hiring as the title, and another one that says, why you should write down everything.
[00:13:07] So, here's where hiring, why you should write down everything, and then the rest of the three or four, come from the filesystem, here. So again, next.js doesn't not care where you pull this from, right? I pull something from a file system, I pulled another one from our fake CMS, you can pull something from an API somewhere.
[00:13:29] Wherever you want, you can totally do it, this is an async function, you can do whatever you want. And eventually I'm going to show you how we can actually access the database and one of these functions which is really crazy if you think about it.