last updated: May 05, 2023
5 minute read
How I Built My Blog
I'm a big fan of tech blogs. Compared to a video or dev talk, they're often shorter, more intentional, quicker to skim when needed, and when dealing with difficult content, easier to review and re-read. They're also fun to write – especially when most of your typing is coding. I've been wanting to write my own blog for some time now, and with a break in some of my other side-projects, I finally got around to it.
This post shouldn't function as a step-by-step tutorial, but instead a high-level overview of the tech stack I use along with a few of my thoughts.
Client
I decided to use Next.js as my front-end framework because of its optimization for static site generation. With SSG, every page is pre-rendered at build time and served to the user immediately. This is distinct from server side rendering, which renders the requested page at request-time. Since my blog renders the same content for every user, it makes a great use case for pre-rendering the site with SSG.
I looked into some other frameworks that specialize in SSG, but Next.js had the best combination of popularity – which goes hand-in-hand with online resources – and a good ratio of framework-specific quirks to features. In other words, for all the features you can access with Next.js, you have to learn very little framework boilerplate.
Update: I've since converted all my pages to use server side rendering (SSR) to allow for a more seamless dark mode experience (i.e. without a white flash). See my article Dark Mode in Next.js Part 2: A Server-Side Approach for a deeper dive into the perils of dark-mode. Thankfully, Next.js has great support for SSR as well, and I haven't yet regretted my choice in framework.
Design
I decided to use tailwindcss as my CSS "framework". I've experimented in the past with css-modules, plain scss, and vanilla extract, but I've found tailwind to be my favorite so far.
Design isn't my strong suit, so I decided to go with daisyui as my component
library. I mostly write my own components, but daisyui has some great color themes that I use (the
theme for this site is corporate
!) Daisyui also has great integration with tailwind, so I can use
classes like text-primary
instead of text-gray-200
.
I write my blog posts in Markdown, which has an awesome syntax for writing, and some really nice
default styles. More specifically, I use mdx, which has support for JSX
components. This may be a little overkill for my uses, but it makes it really seamless to use Next's
Link
along with some of my own reusable components.
Atropos
For the 3D parallax image on the homepage, I use Atropos. The library is surprisingly minimal, and the documentation bare-bones, so I've had to reverse engineer a few of features I wanted from the examples on their site. This blog is open source, so maybe I can save you from doing the same.
Check out the AtroposBorder
component
to recreate the 3D borders on the github cards on the homepage.
Server
On the server side of things, I use Prisma as my database, Next.js's API routes, and React Query to handle my data fetching. I do most of my fetching server-side to prevent any loading states, and I've been really happy with React Query's SSR capabilities.
Fetching on the server is a bit of a trade off - the data fetching blocks the page from being sent to the user until it's completed, so the user sees a blank screen for longer than they would if I did my data fetching client-side. However, since my database and Next.js server are hosted on the same digital ocean droplet, the data fetching should be nearly instant. I think it's worth a slightly longer blank screen to prevent a loading skeleton + layout shift, but YMMV.
I implemented my OAuth authentication manually for the fun of it, since the only data I store is the user's public github username. To handle any sensitive user data, I'd probably use a battle-tested OAuth solution like NextAuth instead.
Devops
On the devops side of things, I host my blog on a digital ocean droplet – the cheapest one available. I use nginx as a proxy for my Next.js server, and certbot to set up my ssl certificate.
To manage my production code, I use this setup to push
changes to the server with the command git push server
. It's bare-bones, low-level, and simple to
use.
For my basic continuous integration, I wrote a deploy script that builds the site locally to make sure everything's working, run a handful of end-to-end tests with playwright, backup my database to my local machine, push to github, and push to the server.
I use pm2 to manage my Next.js server, and I restart the service automatically when new code is pushed – it took just a few lines added to the post-receive hook.
Check out this other post I wrote on my minimal approach to continuous integration for more info!
Bonus: Some of my Favorite Blog Posts From Other Authors
- A Complete Guide to useEffect
- Remix vs Next.js
- Fix the slow render before you fix the re-render
- Why Efficient Hydration in JavaScript Frameworks is so Challenging
- React Server Components and Remix
- The Ultimate Guide to handling JWTs on frontend clients
- Stop using JWT for sessions
- The Grug Brained Developer
You can get a pretty good idea of my interests from this list!
you might also like:
Server Side Rendering vs React Server Components
November 08, 2022
Comparing, contrasting, and exploring how the two can be used to compliment one another