Introduction
Over the past few months, I've been intermittently upgrading my blog website. As it nears completion, I'm taking this opportunity to summarize and finalize the transition.
The Tech Stack
Next.js
15.0.2
React
19.0.0-alpha.3
MDX
3.0.1
Tailwindcss
3.4.0
Shiki
0.15.0
Framer Motion
12.0.0-alpha.0
TypeScript
5.5.0
Rocketbase
0.22.22
PostgreSQL
16
Why React and Next.js
Next.js 15 might seem like overkill for a simple blog. However, I chose it deliberately for its unified development experience - it reduces context-switching between different tools and makes the codebase more maintainable in the long run.
However, I must admit that Nuxt with TSX offers a more streamlined developer experience and reduced cognitive overhead in my opinion.
Content management
After exploring various CMS solutions, I realized I needed more flexibility and granular control over my content than what they could offer.
For example, when working with WordPress's built-in editor, I found myself constrained by its limitations. Adding custom components required writing mixed PHP and HTML code, which not only felt cumbersome but also made the codebase harder to maintain.
Instead, I prefer writing content directly in a code editor (VSCode / Cursor / Neovim). This approach gives me complete control over the content structure, allows me to seamlessly integrate interactive elements, and maintains a straightforward publishing workflow - all while keeping my development environment consistent.
However, MDX does have its drawbacks. The main inconvenience is that I need to commit and push changes to the remote repository every time I want to update content. This workflow can feel cumbersome compared to traditional CMS solutions that offer web-based editors.
Note: Next.js App Router's turbo mode is currently incompatible with MDX. This means you'll need to disable turbo mode if you want to use MDX in your Next.js 15 application.
Styling and CSS
Tailwind CSS
I chose Tailwind CSS for styling because it's currently the most popular CSS framework. It offers several key advantages:
- Rapid prototyping - In most cases, I can style components without writing custom CSS or switching between JavaScript and CSS files
- AI-friendly - The class-based approach works well with AI code generation tools
However, some developers have valid concerns about Tailwind:
- No CSS code splitting - This can make it more challenging to optimize bundle sizes
- Complex components can become messy - The inline class approach can reduce maintainability and make it harder to maintain a single source of truth for styles
But I think it's a good trade-off for the benefits it brings.
Font
I use Inter as the font for this blog.
Shiki - Code Highlighting
For code highlighting, I chose Shiki, a powerful syntax highlighter currently maintained by @antfu.
Shiki (式,meaning "style" in Japanese) is an elegant and robust syntax highlighter powered by TextMate grammar and themes - the same technology behind VS Code's syntax highlighting. It delivers precise and efficient highlighting for virtually all mainstream programming languages.
What sets Shiki apart is its maintenance-free nature. There's no need to manage custom regular expressions, CSS rules, or HTML markup. Better yet, your syntax highlighting automatically stays up-to-date as VS Code's language support and themes evolve.
Additionally, Shiki performs its syntax highlighting at compile time rather than runtime, which means there's no performance overhead when users view your code blocks. This is particularly beneficial for blogs and documentation sites where code snippets are common.
Interactive Widgets
Why I utilize MDX for this blog is that I can write interactive widgets in MDX. and I can use Framer Motion to animate them.
For Example, I can write a simple interactive widget like this:
It's a simple number counter with a slider that allows you to adjust the rotation of the number counter.
Value: 0
Rotation: 0.0°
Traditional CMS platforms often limit component usage since they typically don't support React components natively. In contrast, MDX allows me to seamlessly integrate any React component from my codebase, which is why I chose MDX along with Framer Motion for this blog. This flexibility enables me to create rich, interactive content while maintaining a consistent development experience.
Backend
For the backend, I chose Rocketbase, a forked version of PocketBase. Rocketbase serves as a versatile database solution that helps me manage various aspects of my blog, including:
- Post metadata (categories, tags)
- Image assets, resizing
- Structured data that would be cumbersome to maintain in markdown tables
This setup provides a robust and flexible backend while keeping the development process streamlined.
I really believe in keeping things organized - that's why I love having a powerful backend doing most of the heavy lifting, while the frontend focuses on creating a great user experience. Think of it like a restaurant where the kitchen (backend) does all the complex food prep, while the waitstaff (frontend) ensures a smooth dining experience!
You might wonder, "Why not just use Next.js for everything?" Well, I've found that Go is just fantastic for backend work - it's reliable, fast, and has been battle-tested by many developers before me. It feels like using a trusted family recipe that you know will turn out great every time.
So here's how I've set things up: Next.js handles all the user interface magic - making things interactive and engaging. Meanwhile, my Go backend takes care of all the complex behind-the-scenes work. It's like having the best of both worlds - a friendly, interactive frontend powered by Next.js, supported by a rock-solid Go backend. This setup lets me focus on creating the best possible experience for my blog's visitors!
References
- This blog was inspired by Josh Comeau's blog