Christopher Waddington
The question begins with how do you make a blog in NextJS? I've done some research and decided on using the following libraries.
To understand how this works you need to understand NextJS Static Site Generation (SSG) and 2 specific methods:
getStaticPaths
getStaticProps
Let's take a look at these first
Static Site Generation is a feature provided in the NextJS framework that allows you to pre-render pages at build time. This generates static HTML files for each page of the application and can be served directly by a web server or a CDN. With SSG, the server renders the page at build time rather than on each request to the server.
But how do I populate my pages at build time? This is where dynamic data and our 2 functions, getStaticPaths
and getStaticProps
come in to the picture.
Dynamic data, is the idea that you can fetch data from APIs or databases during the build process then use that data to pre-render the pages. For example,
you can fetch blog posts from an API and generate static blog pages with their content. In our case, instead of reading from an API, we will simply be
reading from our local file structure.
getStaticPaths
This function is called in the context of the SSG at build time. It's purpose is to define that paths for which NextJS will generate static pages. During the build time, NextJS looks for components with this function defined. It then calls it to generate an array of paths based on the logic within the function. NextJS then pre-renders static pages for each path in this array. The pages are then stored and ready to be served at runtime.
Here is our getStaticPaths
function:
export async function getStaticPaths() {
const postsDirectory = path.join(process.cwd(), 'data', 'articles');
const fileNames = fs.readdirSync(postsDirectory);
const paths: Params[] = fileNames.map((fileName) => ({
params: { slug: fileName.replace('.md', '') },
}));
return { paths, fallback: false };
}
getStaticProps
This function is also callled in the context of the SSG at build time for each each path returned in the array by getStaticPaths
. When you define this function in a component, NextJS will pre-render that page with the specified data fetched at build time. For each page with this defined, it will be called and fetch the necessary data required for pre-rendering the page. This data is than passed as props to the respective page component to be rendered.
Here is our getStaticProps
function:
export async function getStaticProps({ params }: { params: { slug: string } }) {
const { slug } = params;
const filePath = path.join(process.cwd(), 'data', 'articles', `${slug}.md`);
const fileContent = fs.readFileSync(filePath, 'utf-8');
const { content, data } = matter(fileContent);
const htmlContent = marked.parse(content);
return { props: { content: htmlContent, data } };
}
In this function you see that we are reading fileContent
using the fs library and then using matter
on that content to parse out that {content, data}
. We then use marked
to parse the content into htmlContent
. Let's talk a little about these libraries.
gray-matter
This is a JS library that is used with Markdown files (.md) to parse and extract front matter. Front matter is metatdata that is typically placed at the beginning of a .md file and provides additional information about the content such as title, slug, author, tags, date, etc. This library lets us extract that information from our articles and access it as an JS object.
marked
This is a JS library that is used for parsing and rendering Markdown content as HTML. It takes Markdown text as input and converts it into HTML markup that can be rendered in a browser. We use this to convert
our articles ( which are written as a markdown file ) into HTML elements that are rendered in our <Article/>
component. We then use tailwind inside our component for styling 😉
// Our Blog Page Component ( style this using Tailwind)
export default function BlogPost({ content, data }: BlogPostProps) {
return (
<>
<Article title={data.title} author={data.author} content={content}/>
</>
);
}
With these elements we can create Markdown files in our data/articles folder, read and parse them using gray-matter
and marked
. Then use getStaticProps
and getStaticPaths
to pre-render them
in our NextJS build. This can then be accessed via their file names at chrislikescode.com/blog/articlename. What I would like to do next is create a main blog page that can render a feed to these
blogs, add in the abilitiy for people to like, comment, share ( which will require some persistence - hello mongodb 👋) and then get all this linked up in my main navigation.