一次博客 SSG 静态化改造实录
记录一次从纯 SPA 到 SSG + SPA 水合的演进过程
更新于 2026.08.07
本文目录 9 节

前言,阅读本文前,请熟悉以下英文缩写。
SPA:Single Page Application,单页面应用
CSR:Client-Side Rendering,客户端渲染
SSR:Server-Side Rendering,服务端渲染
SSG:Static Site Generate,静态站点生成
背景:为什么要折腾 SSG?
我的博客最初是一个典型的SPA架构:
- 前端:
Vue 3+Vite+TypeScript - 后端:
Spring Boot - 文章内容:
Markdown存在数据库中 - 渲染方式:纯
CSR(客户端渲染)
这个架构对「人」非常友好,但对「搜索引擎」和「爬虫」并不友好。
问题
访问文章页时,页面源代码里只有:
<div id="app"></div>
文章内容完全依赖 JS 渲染。 结果就是:
- 搜索引擎抓不到正文
- AI 搜索 / AI 摘要工具“看不到内容”
- 搜索引擎站长工具给出负面评价
- 在QQ、微信等平台发送链接解析不出文章标题
于是,一个目标非常明确的需求出现了:
在不重构整个前端的前提下,让文章页对爬虫是“完整 HTML”。
方案选择
在动手之前,我给自己设定了几条硬约束。
- 不引入
Nuxt/SSR(成本太高) - 不重写现有 Vue 页面
- 只改造文章详情页
- 普通用户体验不能明显变差
方案调研
在调研了几种方案后,大致有这些选择:
| 方案 | 问题 |
|---|---|
| SSR(Nuxt) | 架构侵入性太强 |
| 构建期预渲染 | 动态文章不适合 |
| Headless Chrome | 资源消耗大 |
我并不想把太多精力放在前端上,Nuxt和Headless Chrome的改造是绝对不考虑的。并且由于我这是动态站,并不是JavaGuide这种文档站,所以也不太适合用VuePress、VitePress这种工具。
方案实现过程
我的博客文章本质上是:数据库中的Markdown+ HTML模板,前端用Node.js脚本从后端取出文章信息提前渲染好HTML,在访问时根据UA判断是爬虫还是访客,爬虫则展示SSG、访客则展示SPA。这样保证文章内容可被抓取同时访客还有良好的交互体验。
弯路一:通过UA判断爬虫
本想通过UserAgent判断百度蜘蛛和BingBot等爬虫,但测试后发现效果不佳。因为OpenAI以及其他一众AI爬虫并无固定的UA,无法识别这些爬虫。在AI时代的当下,应当对这些AI访问网页的爬虫工具提供良好支持。
弯路二:统一返回SSG、评论区CSR加载
这一步通过预设HTML模板,返回与SPA长得差不多的SSG,评论等用CSR实现。逻辑上是差不多的。
为了适配 SSG 页面,前端不得不开始处理:
- 判断当前是否运行在 SSG 页面中
- 区分「静态首屏」和「完整 SPA」
- 某些逻辑只能在 CSR 阶段执行
虽然这些都能解决,但我很快意识到:前端复杂度在被动上升。
最终:SSG 首屏 + SPA 自动切换(水合)」
核心思路:
- 所有请求先返回 SSG 静态页面(爬虫友好)
SSG页面内嵌JavaScript,检测到普通浏览器后自动跳转到 SPA- 爬虫不执行 JS,直接抓取静态内容
这样一来,实现反而简单了,用户体验也更好了。 SSG 模板内嵌脚本:
<script>
(function() {
// 已经带有 spa=1 参数说明是跳转后的请求,不再处理
if (window.location.search.includes('spa=1')) return;
// 跳转到 SPA 版本
var articleId = {{articleId}};
window.location.replace('/article/' + articleId + '?spa=1');
})();
</script>
Vue Router 清理参数:
router.beforeEach((to, _from, next) => {
// 清理 SSG 水合跳转时添加的 spa=1 参数
if (to.query.spa === '1') {
const { spa, ...restQuery } = to.query;
next({ ...to, query: restQuery, replace: true });
return;
}
next();
});
这个方案带来了很多优势: 功能方面,
| 特性 | SSG 首屏 + SPA 水合 |
|---|---|
| SEO | 爬虫获取完整静态内容 |
| 首屏速度 | 静态 HTML 秒开 |
| 用户体验 | 自动切换到完整 SPA |
| 维护成本 | 无需维护 UA 列表 |
| 可靠性 | 100% 可靠,无边界情况 |
安全方面,
| 层级 | 保护机制 |
|---|---|
| SSG 层 | 只有 status = "published" 的文章才生成静态 HTML |
| Nginx 层 | 静态文件不存在时回退到 SPA |
| 后端 API 层 | 未发布文章需要登录才能访问 |
成果
到此,本站的SSG改造已经完成。将文章链接喂给AI等可正常解析内容。
评论
无需登录,审核通过后公开。只有博主可以回复。
正在加载…
已公开的评论