My blog is actually two applications: a frontend and a backend. The frontend used to be a client side rendered (CSR) application, which worked fine for my usual work on internal tools. But when I wanted link unfurls on platforms like Discord and Slack, I realized I needed to switch to server side rendering (SSR).
Why CSR Wasn't Enough
CSR apps are fast to develop and easy to deploy. The browser loads a minimal HTML file, grabs a JavaScript bundle, and builds everything from there. For internal dashboards? Perfect.
But for public-facing content where metadata matters—like link previews—CSR just doesn't cut it.
Here's what a typical CSR request looks like:
Slack and Discord bots aren’t going to run your JavaScript to extract meta tags. They just want the HTML as-is.
The Big Switch: Nuxt
So I moved my frontend to Nuxt which is more purpose built for SSR applications. For the most part it feels just like Vue + Vite.
This wasn’t just a framework swap, though. It meant rethinking my whole authentication setup.
localStorage, Meet Server
In the CSR world, I stored authentication tokens in localStorage
. It’s simple:
localStorage.setItem('access_token', token)
But SSR means the server is responsible for rendering pages. And guess what? Servers can't access
your localStorage
.
The Problem
So I had to refactor my auth to use HTTP cookies, which are shared with the server via headers.
GET /dashboard
Cookie: access_token=abc123
It’s a more complex setup (and yes, secure cookies with HTTP-only flags and proper domain scoping are a thing I had to think about.)
Side Effects and Downtime
This migration wasn't without casualties:
- 💥 Pages 500-ing in production
- 🔐 Users randomly getting logged out
- 🐛 Inconsistent auth state between client and server
I worked through the bugs with the help of Cursor, and things are stable now. I'm even reaping the benefits:
- ✅ Instant meta tags for link unfurls
- ✅ Faster first paint for users
- ✅ Cleaner URL handling via Nuxt routes
Oh, and the Source is Available
Now that things are working, I'm also using this moment to make my project source available. There's no license on it (yet?)—so feel free to browse, peek, and maybe file an issue if you’re feeling generous. The main reason I'm doing this is so that other people can see how I'm leveraging and using LLMs on a codebase.