项目概述
一直想有一个属于自己的地方,记录技术思考和日常感悟。试过各种平台,最终还是觉得自建博客最自由。这篇文章记录整个博客从设计到搭建的完整过程。
技术选型
博客的定位是混合型(技术 + 随笔 + 生活),所以技术栈需要兼顾写作体验和开发灵活性:
- Next.js 14 — App Router + 服务端组件,零 bundle 开销
- MDX — Markdown + React 组件,文件系统存储,写作像写文档
- Tailwind CSS — 原子化 CSS,快速实现设计稿
- TypeScript — 类型安全,减少低级错误
- Vercel — 一键部署,自动 CI/CD
不使用数据库,所有内容都存在文件系统里。纯前端,无后端 API,保持极简。
视觉风格:渐变 + 玻璃拟态
整体采用紫色渐变为主色调,搭配玻璃拟态(Glassmorphism)卡片效果。
配色方案
| 用途 | 颜色值 |
|---|---|
| 主渐变 | #667eea → #764ba2 |
| 背景渐变 | #f0e6ff → #faf5ff |
| 深色 Footer | #1a1a2e |
| 卡片背景 | rgba(255,255,255,0.7) + 毛玻璃模糊 |
| 正文文本 | #333 |
核心设计特征
- 玻璃拟态卡片:半透明白底 +
backdrop-filter: blur(10px) - 渐变标签:紫渐变胶囊形状,白字圆角
- 大圆角:16px 卡片圆角,8px 小组件圆角
- 柔和阴影:
rgba(118,75,162,0.08)紫色调阴影 - 系统字体:
system-ui,加载零延迟
架构设计
数据流
content/*.mdx → lib/posts.ts (解析 frontmatter) → 首页/标签页渲染
↓
app/posts/[slug]/page.tsx → 文章详情渲染 (MDX)
项目结构
blog/
├── app/
│ ├── posts/[slug]/page.tsx # 文章详情页
│ ├── tags/[tag]/page.tsx # 标签筛选页
│ ├── layout.tsx # 全局布局
│ ├── page.tsx # 首页
│ └── not-found.tsx # 404 页面
├── components/
│ ├── Header.tsx # 导航栏
│ ├── Footer.tsx # 页脚
│ ├── PostCard.tsx # 文章卡片
│ ├── SearchBar.tsx # 搜索组件
│ └── MDXComponents.tsx # MDX 自定义组件
├── content/ # 文章文件
└── lib/posts.ts # MDX 解析工具
MDX 渲染管线
每篇文章的渲染经历了三层处理:
- 文件读取 —
fs.readFileSync读取.mdx文件 - 编译 —
compileMDX解析 frontmatter,应用 remark/rehype 插件 - 组件注入 — 自定义
MDXComponents覆盖默认 HTML 元素样式
const { content } = await compileMDX({
source,
options: {
parseFrontmatter: true,
mdxOptions: {
remarkPlugins: [remarkGfm],
rehypePlugins: [rehypeSlug, rehypeHighlight],
},
},
components,
});
💡 关键经验:
next-mdx-remotev6 的 API 与旧版本不同,使用compileMDX而非serialize,插件需要通过mdxOptions传入。
页面实现
首页
渐变紫色背景 + Hero 标语文字,文章以响应式 auto-fill 网格排列,每行 2-3 张玻璃卡片。
文章详情页
标题区淡紫渐变背景,正文 720px 居中放在白色玻璃卡片内:
- 标题:紫色系大字号
- 段落:1.8 行高
- 引用块:紫色左边框 + 淡紫渐变背景
- 代码块:
atom-one-dark主题语法高亮
标签筛选
与首页相同布局,通过 URL 参数过滤文章列表。
踩坑记录
MDX 组件未生效
最初直接用 <MDXRemote source={source} /> 渲染,自定义组件完全没有生效。原因是:
- 没有传入
componentsprop 给MDXRemote next.config.mjs中的 remark/rehype 插件只对路由级 MDX 生效,不影响next-mdx-remote
修复方式是使用 compileMDX 并显式传入自定义组件和插件配置。
代码块看不清
代码块背景是深色 #1a1a2e,但忘记导入 highlight.js 的主题 CSS,导致文字几乎是不可见的浅灰色。解决方案是在 globals.css 中导入 atom-one-dark 主题:
@import 'highlight.js/styles/atom-one-dark.css';
当前功能清单
- 文章列表页(按日期倒序)
- 文章详情页(MDX 渲染 + 语法高亮)
- 标签分类筛选
- 搜索功能
- 响应式设计(移动端友好)
- 自定义 404 页面
后续可能考虑评论系统,但目前保持极简就好。