Building a Portfolio Site
Intro
Intent and vision.
I created this portfolio site, specifically the blog section, to share discourse on software engineering topics and discuss projects I'm working on - or have previously worked on. I'm a regular engineer who loves to learn, build meaningful projects, and enjoy this ride along the way. If you're on a similar path - welcome!
Prefer to just jump into the code for this project? Check out the GitHub repository. Want a deeper dive on what frameworks and libraries were used, how it's hosted, and so on...follow below for more details!
Next.js
One of many React frameworks.
Even one of many web frameworks, like Angular or Vue.js. Why Next.js and a React framework?
First, I simply wanted to learn a React framework. My industry experience has been in other frameworks for full-stack web development — like Angular and Vue.js. why not use this as an opportunity to learn something different!
The second reason can be deemed more interesting. You can serve a production Next.js application a few different ways. You can statically serve the app using a static site generator. Or you could server side render components and send them to the client. Even further, you could serve a full-stack Next.js application, backend and frontend all in one.
You might wonder, "Isn't this framework a little overpowered for a simple blog?" I completely agree. It is overboard. However, the SSG is appealing here since it serves the purpose of delivering content quickly. But if I ever want to evolve from just a static blog, those options above are still on the table with Next.js. You want to take it full-stack with a contact form, interactive project demos, and some REST apis for visitors to sample? Those features are available.
Useful Libraries and Frameworks
Because building everything from scratch is unreasonable.
Styling:
For styling throughout the portfolio site, I used tailwindcss. Great experience with the CSS framework. Very intuitive to use. It can feel a little clustered with all the tailwindcss utility classes in your markdown. With some effort, I’m sure I could clean that up — but for a small, simply styled app, it’s fine. In addition, @tailwindcss/typography is a plugin to style your blog prose uniformly and easily.
Content with MDX:
Creating the blog content was easy. write your content as MDX, a superset of Markdown, which is a markup language for formatting text. When writing long posts with lots of links, headers, emphasis, and so on, it can be easier than writing HTML.
MDX integration:
Recall that Next.js does not support MDX out-of-the-box. How do we convert the content from our MDX files into usable React components? On top of that, is it possible to dynamically visit posts, or does a page per MDX file need to be made? Well...this part ended up not being trivial. Luckily, Next.js offers excellent documentation on integrating MDX into your application.
The steps are as follows:
- Set up the necessary configuration to import and render MDX files in your route structure.
- Read the file, if you have frontmatter, parse it. I liked the gray-matter plugin.
import matter from 'gray-matter'
function parseMetaData(rawContent: string) {
const { data } = matter(rawContent)
return { meta: data }
}
function parseContent(rawContent: string) {
const { content } = matter(rawContent)
return { content }
}
- Convert the markdown to a usable React component.
import path from 'path'
import { evaluate } from '@mdx-js/mdx'
import * as runtime from 'react/jsx-runtime'
export async function getPost(slug: string) {
const filePath: string = path.join(POSTS_PATH, `${slug}.mdx`)
const rawContent: string = readMDXFile(filePath)
const { content } = parseContent(rawContent)
const { default: Post } = await evaluate(content, {
...runtime // Provides JSX transformation for MDX
})
return { Post }
}
The runtime
object contains the React JSX runtime, which provides the necessary functions for MDX to compile your
markdown content into executable React components. This is imported from React's built-in JSX runtime.
- display the component on your desired page
import { getPost } from '@/lib/mdx'
export default async function Page({ params } : { params: { slug: string} }) {
const { slug } = await params
const { Post } = await getPost(slug)
return (
<MdxLayout>
<Post />
</MdxLayout>
)
}
Deploying
Sometimes the simple option is the best option.
There are a number of ways to deploy a Next.js application. Netlify. AWS. If you want to get technical with it, you could containerize the application with Docker and self-host. That's a great feature of Next.js — it's flexible about hosting options.
Out of simplicity, I went with Vercel. They created Next.js, have a generous free tier, excellent developer experience with automatic deployments from Git, built-in analytics, and seamless handling of all Next.js features. This allows one to focus on content and future projects, instead of infrastructure.
You will need to buy a domain name unless you are accepting of Vercel's provided domain. I went with namecheap to purchase alexmccairel.dev for this site and added it to my Vercel account. The process was straightforward. Buy the domain, configure DNS records in namecheap to point to Vercel's servers, and add the domain in your Vercel project settings. In less than five minutes, the custom domain was live with automatic SSL certificates handled by Vercel.
Having a custom domain makes a significant difference for a portfolio site. Instead of sharing
portfolio-site-ds7n7vrv5-amccairels-projects.vercel.app
(quite the mouthful), visitors can simply go to
alexmccairel.dev. It's cleaner, more memorable, and more professional — well worth the ~$15/year investment.
Conclusion
A fun framework.
Thank you for taking the time to read. I enjoyed explaining Next.js and why I chose it as a framework for building my portfolio site. I hope it helps anyone building a similar application. It's a great React framework with plenty of community support for your web application needs. It's more than just a static site generator. It can support full-stack capabilities. This makes it a respectable choice for a software engineer like myself, who may want to add more advanced features down the line. Cheers, thanks for joining me on the deep dive and feel free to reach out if you are implementing something similar!