从零到一:我的个人博客开发历程
吾生也有涯,而知也无涯。—— 庄子
前言
作为一个业余前端开发者,搭建一个属于自己的博客系统,一直是心中的执念。不是没有现成的方案——WordPress、Hexo、Hugo 一抓一大把,但总觉得少了点什么。少了那种从零开始、一行一行敲出来、每一个像素都由自己掌控的感觉。
于是,我开始了这段漫长的博客开发之路。
一、起点:选择 ThriveX
最初接触的是 ThriveX,一个现代化的博客管理系统。它提供了后端 API 和管理后台,前端可以自由发挥。这正是我想要的——不需要自己写后端,但前端完全可控。
技术栈很快确定下来:
- 框架: Next.js 16(App Router)
- UI: React 19 + Tailwind CSS v4
- 动画: GSAP
- 图片优化: sharp + next/image
- 部署: Vercel / Docker
目标很明确:做一个有自己风格的博客,不是千篇一律的主题模板。
二、设计风格:水墨与赛博的碰撞
我不想做又一个极简白底博客,也不想做暗黑科技风。最终选择了一个比较小众的方向——水墨赛博。
- 字体用的是「Noto Serif SC」,自带书卷气
- 色彩以深色为底,点缀铜金和青碧
- 首页有一个水墨粒子动画的 Hero 区域
- 页脚有一只墨笔画的小动物,跟着页面 sticky 在底部
这个风格说不上惊艳,但至少有辨识度。
三、核心页面的开发
3.1 首页
首页是博客的门面,花了不少心思:
- Hero 区域: 全屏水墨风,「墨·Loong」的大字标题,下方是粒子动画
- 轮播图: 展示置顶或推荐文章
- 精选文章: 从后端
/api/article/hot获取热门文章,3 列卡片布局 - 最新文章: 分页加载,带左右滑动翻页动画
- 时间线: 文章的时间轴展示
- 最新评论: 展示访客的评论
每个区域都用了 Suspense 做流式加载,首屏不会被一个慢接口拖住。
3.2 文章详情页
这是博客最核心的页面:
- 全屏封面 Hero: 文章封面铺满整个首屏,标题和元信息浮在上面
- 目录侧边栏: 自动解析 h2/h3 生成目录,滚动时高亮当前章节
- 阅读进度条: 顶部的渐变进度条,实时显示阅读位置
- Markdown 渲染: 支持 GFM、数学公式、代码高亮
- 评论系统: 支持嵌套回复,QQ 邮箱自动获取头像
- 上下篇导航: 文章底部的前后翻页
3.3 其他页面
- 标签云: 标签按文章数量缩放大小,点击跳转到该标签的文章列表
- 数据总览: 文章、标签、友链、评论的统计面板
- 设备清单: 展示我的设备,支持图片灯箱放大
- 足迹地图: 高德地图标记我去过的地方
- 友链: 分组展示友情链接
- 说说: 类似朋友圈的时间轴动态
- 留言墙: 访客留言板
- 鱼塘: RSS 订阅源聚合
四、踩过的坑
4.1 Lenis 平滑滚动的噩梦
最初引入了 Lenis 库做平滑滚动,效果确实丝滑。但上线后频繁出现一个问题:页面偶尔会卡死,无法滚动。
排查了很久,发现是 Lenis 用 CSS transform 模拟滚动,和浏览器原生的 scrollTop 会产生位置不同步。当两者冲突时,滚轮事件被 Lenis 拦截但不执行,页面就卡住了。
最终的解决方案:移除 Lenis,用 GSAP 的 ScrollToPlugin 替代。GSAP 内部用原生 window.scrollTo,不会出现位置不同步的问题,而且 autoKill: true 可以在用户手动滚动时自动取消动画。
4.2 Emoji 图标的渲染问题
博客里的分类和标签名称带了 emoji(比如 🗂️ 默认分类),但前端用 emoji 做功能图标时,在某些设备上渲染不一致。
解决方案:把所有功能图标替换为 SVG,emoji 只保留在内容数据中。
4.3 SEO 的 Canonical URL
一开始所有页面的 canonical 都指向根域名 https://loongblog.fun,导致搜索引擎认为所有页面都是同一个内容。
修复方式:在 layout 中移除全局 canonical,给每个页面单独设置。动态页面(文章、标签、分类)在 generateMetadata 中根据参数生成。
4.4 图片优化
最初全部用原生 <img> 标签,没有 WebP/AVIF 转换,也没有响应式尺寸。后来把服务端组件中的图片迁移到 next/image,配合 sharp 自动优化。
但对于外部 API 返回的图片(友链头像、鱼塘 RSS 图片),因为域名不可控,无法加入 remotePatterns,只能保留 <img> + loading="lazy"。
五、性能优化
5.1 首页流式加载
把首页拆分成 5 个独立的 Section,每个用 Suspense 包裹。用户先看到 Hero,其他区域异步加载,不会被最慢的接口拖住。
5.2 字体优化
Noto Serif SC 的完整字体文件有几 MB,用 next/font/local 做子集化后,只剩下几十 KB 的 woff2 文件,按需加载。
5.3 图片懒加载
所有非首屏图片都加了 loading="lazy",设备页、足迹页、友链页的图片不会在首屏加载。
5.4 缓存策略
- 静态页面:
revalidate = 300(5 分钟 ISR) - 文章详情:
revalidate = 60(1 分钟 ISR) - 标签/分类列表:
revalidate = 300
六、安全加固
- 安全头: X-Content-Type-Options、X-Frame-Options、Referrer-Policy、HSTS
- API 隐藏: robots.txt 禁止爬取
/api/路径 - XSS 防护: Markdown 渲染用白名单过滤标签
- 环境变量:
.env文件不提交,敏感配置通过环境变量注入
七、从本地到线上
部署用的是 Docker + Vercel 混合方案:
- 前端 Next.js 部署在 Vercel,自动 CI/CD
- 后端 ThriveX Admin 部署在自己的服务器
- 图片存储用七牛云 OSS
- CDN 用 Cloudflare
域名 loongblog.fun,ICP 备案已完成。
八、回头看
这个博客从第一次 commit 到现在,经历了无数次重构。滚动问题改了五六版,SEO 优化做了两轮,图标替换了一批又一批。有时候改一行代码要推三次才能上线。
但每次看到自己的博客在浏览器里打开,那种满足感是用任何现成模板都给不了的。
技术栈会过时,代码会被重构,但这个过程本身,就是最好的学习。
技术栈一览
| 类别 | 技术 |
|---|---|
| 框架 | Next.js 16 (App Router) |
| UI | React 19 + Tailwind CSS v4 |
| 动画 | GSAP (ScrollToPlugin, ScrollTrigger) |
| 图标 | 自定义 SVG |
| 图片 | next/image + sharp |
| Markdown | react-markdown + remark-gfm + rehype-katex |
| 状态管理 | Zustand |
| 地图 | 高德地图 JS API |
| 部署 | Vercel + Docker |
| CDN | Cloudflare |
| 图床 | 七牛云 OSS |
写于 2026 年 6 月,Loong·Blog
评论 (0)