The frontend layer of my personal website tianwei.io.
- Framework: Next.js
- Styling: Tailwind CSS
- MDX Processing: next-mdx-remote
- Data Validation: Zod
- Image Optimization: Cloudinary
- Deployment: Vercel
- Frontend: a Next.js application rendering content from the API dynamically using SSR with optimized caching strategies.
- API Layer: a Hono service (Node.js) that serves content data from the content engine via REST endpoints.
- Content Engine: a dedicated repo that stores, parses and syncs MDX to a remote PostgreSQL database.
Note: previously this site incorporated Contentlayer to manage frontend and content data in a single repo. I have since moved to a decoupled architecture that separates the frontend and backend which allows for better flexibility and scalability.
git clone [email protected]:notbd/tianwei.io.git
cd tianwei.io
pnpm install
# Set up the `.env.local` according to the instructions in `.env.example`
# start local dev server
pnpm run dev
# lint
pnpm run lint
# build
pnpm run buildNotes:
- Cloudinary env variables need to be configured following the instructions for images to show properly.
- Typography and code highlighting are handled by custom React components within
src/components/mdxand via therehype-pretty-codepackage respectively.
The application exposes a revalidation API endpoint at /api/revalidate that invalidates Next.js cache tags and optionally warms the cache by pre-fetching fresh data.
Requests must include a Bearer token matching REVALIDATION_SECRET in the Authorization header.
-
Revalidate a specific post:
POST /api/revalidate
{ "slug": "post-slug" }Invalidates both the post cache tag (
post-{slug}) and the posts list tag, then warms both. -
Revalidate by tag(s):
POST /api/revalidate
Single tag:
{ "tag": "tag-name" }Multiple tags:
{ "tags": ["tag1", "tag2"] }Invalidates the specified cache tags and warms matching routes.
After revalidation, the system automatically warms the cache by pre-fetching data for matching routes. This ensures fresh content is available immediately after invalidation:
poststag: Fetches the posts list and all individual post pagespost-{slug}tags: Fetches the specific post page- Parallel execution: Warming executes in parallel for multiple tags to minimize latency
Warming failures are logged but don't prevent revalidation from succeeding, allowing the cache to be invalidated even if pre-fetching encounters errors.
Source code is licensed under AGPLv3,
The content is licensed under CC BY-NC-SA 4.0.