3.1 KiB
| title | date | tags | excerpt | draft | |||
|---|---|---|---|---|---|---|---|
| Building a Modern Blog with Bun and TypeScript | 2025-10-20 |
|
A deep dive into building a performant, modern blog using Bun's runtime, TypeScript, and server-side rendering. Learn about the architecture decisions and tradeoffs. | false |
Building a Modern Blog with Bun and TypeScript
Why Bun?
Bun is an all-in-one JavaScript runtime that's significantly faster than Node.js for many operations. It includes:
- A blazing-fast JavaScript/TypeScript runtime
- Built-in bundler
- Native TypeScript support
- Package manager
- Test runner
For this blog, the combination of native TypeScript support and the built-in bundler made Bun an obvious choice.
Architecture Overview
The blog uses a hybrid approach:
Server-Side Rendering
All HTML is generated on the server using JSX as a templating language. This means:
- Fast initial page loads - No waiting for JavaScript to download and execute
- SEO friendly - Search engines see fully rendered HTML
- Works without JavaScript - Core functionality doesn't depend on client-side JS
AppShell Pattern
The blog implements an "AppShell" pattern where:
- First visit loads the full page with AppShell (sidebar, header, etc.)
- Navigation replaces only the
<main>content - Subsequent requests send a custom header to indicate AppShell is already loaded
- Server returns just the content, not the full shell
This gives us SPA-like navigation speed with SSR benefits.
Markdown Processing
Blog posts are written in Markdown and processed at build time:
// Simplified example
import { marked } from 'marked';
const html = marked.parse(markdownContent);
The plugin:
- Scans the content directory
- Parses frontmatter (title, date, tags, etc.)
- Converts markdown to HTML
- Stores everything in SQLite for fast queries
Performance Results
The result? Page loads under 128KB including:
- All HTML
- All CSS (inlined)
- Minimal JavaScript for interactivity
First contentful paint happens in under 100ms on a fast connection.
Developer Experience
With Bun's --watch flag, the entire development workflow is seamless:
bun run --watch ./index.tsx
This watches for changes and hot-reloads the server. Combined with the markdown plugin, changing a blog post immediately reflects in the browser.
Lessons Learned
What Worked Well
- JSX for templating - Familiar, type-safe, and no new syntax to learn
- SQLite for search - Fast, embedded, and perfect for a small blog
- Bun's speed - Development is incredibly fast
What Could Be Better
- Hot reloading - Would love client-side HMR for styles
- Build step - Currently all processing happens at runtime
- TypeScript types - Virtual modules need proper type definitions
Conclusion
Building with Bun has been a great experience. The performance is excellent, and the developer experience is top-notch. If you're building a new project and want to try something modern, I highly recommend giving Bun a shot.
The code for this blog is open source - check it out on GitHub!