为什么我用手写静态页面做个人网站

我把这个网站从零写了一遍,没有用 Astro,没有用 Next.js,没有 node_modules。构建脚本是几个 .mjs 文件,依赖数量是零。

这不是复古趣味。是我先想清楚了一件事:个人网站的 SEO 上限由最终 HTML 决定,不由框架决定。

搜索引擎看到的是什么#

爬虫拿到的是一段 HTML 文本。它关心的东西就那么几样:

  • <title><meta name="description"> 是否准确、是否唯一
  • <link rel="canonical"> 是否把重复 URL 收敛到一个地址
  • hreflang 是否成对、是否自引用、是否只有一个 x-default
  • 结构化数据是否自洽,@id 是否稳定
  • 首字节到可读内容有多快
  • 站内链接能不能走到每一个页面

这份清单里没有任何一项写着「用什么框架生成」。Astro 生成的静态 HTML 和我手写的静态 HTML,在爬虫眼里没有区别——如果两者内容一样的话

那框架的价值在哪#

写作体验。这是真实的价值,我不否认。

Astro 的内容集合有类型检查,改一个组件全站生效,热更新,图片自动优化。文章多到几百篇时,这些是刚需。

但这些收益作用在身上,不作用在排名上。我在决定的是:为了写作体验,值不值得引入一整套工具链。

我的权衡#

对这个站,不值得。理由有三个:

第一,SEO 逻辑我要自己掌握。 框架的 sitemap 插件、SEO 组件都很方便,代价是我不知道它到底输出了什么。而 hreflang 写错、canonical 指错、tag 页被大量索引成重复内容——这些问题不会报错,只会在半年后表现为流量不涨。我宁愿这段逻辑是我自己写的、能读懂的。

现在整个 SEO 层集中在四个文件里:路由表决定所有 URL,head.mjs 生成所有 meta,schema.mjs 生成所有结构化数据,feeds.mjs 生成 sitemap 和 robots。要检查 canonical 有没有问题,我读一个函数就行。

第二,依赖是长期成本。 一个 Astro 项目装完大约 300 个包。它们会过期、会有安全公告、会在两年后因为某个 breaking change 让我花一个晚上升级。个人网站的生命周期按十年算,我不想每年为它维护一次工具链。

零依赖的另一面是:这个项目两年后 git clone 下来,node src/build.mjs 一定还能跑。

第三,我的文章量不需要。 几十篇 Markdown,一个 300 行的构建脚本足够处理。等到几百篇、需要标签系统联动、需要图片流水线的时候,再迁移——而那时候迁移成本很低,因为内容本来就是普通 Markdown。

手写不等于偷懒#

需要说清楚的是,「不用框架」不等于「少做事」。这个站实现了:

能力实现方式
双语 hreflang路由表统一生成,保证成对且自引用
结构化数据单一 @graph@id 稳定,Person 全站合并成一个实体
sitemap从路由表生成,带 xhtml:link 语言备用
RSS / Atom / JSON Feed每语言一套,全文 + 摘要
Markdown 镜像每个页面一份 .md,给 AI 助手读
目录、脚注、代码块自己写的 Markdown 渲染器,构建期完成
内容校验标题过长、描述缺失、日期倒挂,构建期报错

最后那一项是框架通常不给我的:构建期的 SEO 校验。描述超过 160 字符会警告,博客文章缺少日期会直接失败。这类问题本地看不出来,上线后要等 Search Console 慢慢告诉我。

什么情况下我会换#

我会在这些条件下迁移到 Astro:

  • 文章超过两百篇,手动管理索引开始出错
  • 需要图片流水线(多尺寸、AVIF、模糊占位)
  • 需要评论、订阅表单这类动态功能
  • 开始有别人一起维护,需要更强的约定和类型检查

这些条件现在都不成立,所以现在不迁。

结论#

框架不会让你的网站更容易被搜索到,正确的 HTML 才会。框架让写正确的 HTML 更省力——这是真的价值,但它是开发体验的价值,不是 SEO 的价值。

分清这两件事之后,选择就取决于你的实际规模,而不是取决于当下流行什么。