How I built my website with NextJS

How I built my website with NextJS blog banner image

Recently if you are thinking of creating a blogging platform or portfolio site, you are definitely overwhelmed by the number of tools out there in the market. There are lots of option available, you can investigate which suits best to your needs. First, I have used Gatsby to develop this site and it is working pretty neat for me. But then I decided to recreate this from scratch using NextJS. In this blog post we will be discussing why and how I switched and experience.

Why

Gatsby is really nice and works for most of your needs for blogging platform and portfolio. But I am looking forward to learn NextJS in detail and I thought that migrating this site to NextJS will be great way to start the journey.

Second is, gatsby generates all the pages at build time, I have used Netlify to host gatsby site and it is taking lot of time to publish single article. Although I have heard that gatsby cloud has lots of improvement but had never tried it.

Third, some functionalities that gatsby offers out of the box has learning opportunities. Like you just need to install plugin and mdx content is directly available to you in graphql request. This is useful when you want to start quick, but configuring this on my own is what I want to try out.

And Fourth one is I want to have some dynamic functionalities like hit counter, like, etc...on my site.

Though all the points mentioned above has some kind counterpart available in Gatsby like gatsby cloud offers the functionality of incremental build. So, gatsby fits very well in many cases but in my case I have made up my mind to switch to Nextjs.

Tech Stack

This site uses NextJS. NextJS provides different ways to render page, server side rendering(SSR), static site generation (SSG). As blogs are all static part, so I have used SSG for /blog/[slug] and opinion/[slug] pages.

1export const getStaticPaths = async () => {
2 const blogs = await getAllBlogsMeta();
3 const paths = blogs.map(({ slug }) => ({ params: { slug } }));
4 return {
5 paths,
6 fallback: false,
7 };
8};
9
10export const getStaticProps: GetStaticProps<Blog> = async context => {
11 const slug = context.params?.slug;
12 const post = await getBlogBySlug(slug);
13
14 return { props: post };
15};

This will statically generates pages for all the slugs at build time.

I have used NextJS API routes to make request to add subscriber. I am using Convertkit to store subscribers and send emails.

For styling I used Tailwind. I am planning to use HeadlessUI in future if I need some components like popover, menu, select, etc. But for now I need basic components like link, button which can be styled from scratch with tailwind.

To implement dark mode, I have used CSS variables with tailwind config file.

1:root {
2 --primary: rgb(255, 135, 38);
3}
4
5.dark {
6 --primary: rgb(251, 146, 60);
7}

Then in tailwind config file you can use this variables to extend the theme to use this variables. You can store the theme in local storage based on which add class dark to document. This approach is easily scalable if we want to add more themes in future.

I have used react-feather as icons library. For syntax highlighting on code blocks, I used prism-react-renderer.

I am using Vercel to host this site with custom domain. It is really easy to use, it literally took me just 5 minutes to host and configure custom domain.

Writing Blogs

There are many headless options available like Contentful. Using this you can fetch the your blog and render it. But I have some requirements, I want to use some custom component in my blog posts for demonstration purposes and also in future I want to have more rich set of components to use in blogs. Instead of limiting this platform to just use bold, italic, and some other that this rich editors provide.

I have another option available to solve the problem. That is create react component for each blog post, that way I can use any component. That is completely fine. It is just the matter of choice that while creating content I don't want to wrap everything with html tags, it will feel more like writing one more component then creating content. So, I chose MDX to move forward.

With MDX I can also specify some metadata related to each post known as front-matter. We can separately fetch this front-matter on home page and blogs page where we do not want to show content. Moreover in front-matter you can store tags, category, and every other information related to that blog, which you think will be useful. For example you would like to store published on or updated on in front-matter to sort the blog on that field.

With Nextjs

There are mainly two major ways to integrate MDX with Nextjs.

  1. @next/mdx - This is the official way next mentioned
  2. mdx-bundler - By Kent C Dodds

I decided to go with Kent's mdx-bundler, there is no special reason for the choice. It is build with esbuild which is a currently a buzz word, So I decided to go ahead with this.

mdx-bundler provides a way to fetch front-matter too. So getAllBlogsMeta method mentioned above looks something like this

1export const getAllBlogsMeta = async () => {
2 const paths = glob.sync(`blogs/**/*.mdx`);
3
4 const blogsFrontMatterPromises = paths.map(async (filePath): Promise<BlogMeta> => {
5 // read content of the file
6 const source = fs.readFileSync(path.join(filePath), 'utf8');
7
8 // Get the file name without .mdx
9 const slug = path.basename(filePath).replace('.mdx', '');
10
11 // Use mdx-bundler to get the front-matter
12 const { frontmatter } = await bundleMDX(source, {
13 esbuildOptions(options) {
14 options.target = ['es2020', 'node12'];
15
16 return options;
17 },
18 });
19
20 return {
21 ...frontmatter,
22 slug,
23 };
24 });
25
26 const blogsFrontMatter = await Promise.all(blogsFrontMatterPromises);
27 return blogsFrontMatter.sort((a, b) => Number(new Date(b.publishedAt)) - Number(new Date(a.publishedAt)))

in the same way we can write getBlogBySlug method with mdx-bundler, to get individual blog based on the slug and display it.

I am also planning to add likes functionality here using Prisma. And will also write a detailed blog on that too once completed. Stay tuned and do not forgot to subscribe for the newsletter to never miss an update. I hope this post is helpful to you in understanding architecture behind this site and decide stack for your own blog or portfolio site.

Subscribe for the newsletter