这个博客是如何被搭建出来的

记录个人研究博客的搭建过程:技术选择、页面组织、部署方式和维护取舍。

这个博客上线之后,搭建过程也值得先记下来。原因很简单:以后肯定还会继续改版、加栏目、补功能,先把第一版为什么这么做写清楚,后面回头看会省很多时间。

为什么选择 Astro + Markdown/MDX + Vercel

目标是做一个轻一点、稳一点的个人博客,写文章时别被工具链拖住,部署时也别加太多维护负担。基于这个目标,Astro 是很合适的选择。

Astro 默认就适合内容型站点。文章页在构建时生成,访问快,部署简单,也不需要单独维护服务端。对个人博客来说,这一套足够用了。

文章内容使用 Markdown,并保留 MDX 支持。大部分文章写 Markdown 就够了,如果以后要放交互组件或更复杂的内容展示,也不用再换方案。

部署放在 Vercel,主要是图省事。导入 GitHub 仓库后,按默认流程构建就能上线,先用免费域名把博客跑起来没有问题。

从零搭建的主要步骤

第一步是先把基础配置定下来:

package.json
astro.config.mjs
tsconfig.json
src/consts.ts
src/content.config.ts

package.json 里只保留必要脚本:devbuildpreviewastro。依赖也控制在最少范围:Astro、MDX 集成、sitemap 集成和 TypeScript。

第二步是把页面结构搭起来。这个博客现在有:

  • 首页 /
  • 文章列表页 /posts/
  • 文章详情页 /posts/[slug]/
  • 分类页 /categories/
  • 标签归档页 /tags/[tag]/
  • 项目页 /projects/
  • About 页面 /about/

第三步是补内容结构。文章统一放在 src/content/posts/,由 content collections 管理。每篇文章都带完整 frontmatter,包括标题、摘要、发布日期、标签和草稿状态。

第四步是把页面样式和右侧栏一起做好。样式集中在 src/styles/global.css,没有使用 CSS 框架。这样调试比较直接,也更适合长期维护。

目录结构说明

目前项目的核心目录如下:

public/
  favicon.svg
src/
  content/
    posts/
      building-this-blog.md
  content.config.ts
  layouts/
    BaseLayout.astro
    PostLayout.astro
  components/
    BackToTop.astro
    PageSidebar.astro
  pages/
    about.astro
    categories/
      index.astro
    index.astro
    posts/
      index.astro
      [slug].astro
    projects/
      index.astro
    tags/
      [tag].astro
  styles/
    global.css
  consts.ts
astro.config.mjs
package.json
README.md

src/pages 负责路由,src/layouts 负责页面外壳和文章页结构,src/components 放右侧栏和回到顶部按钮,src/content/posts 负责文章内容。站点标题、描述、作者和站点 URL 放在 src/consts.ts,后续改站点信息会方便很多。

关键实现点

SEO 放在 BaseLayout.astro 里统一处理。每个页面传入 titledescriptiontypecanonicalPath 后,布局会生成 titledescription、canonical、Open Graph 和 Twitter card 基础信息。

文章页使用 Astro 的 content collections。src/content.config.ts 定义了文章 frontmatter 的 schema,避免文章元信息随意增长或字段拼错。详情页通过动态路由读取集合内容,然后渲染 Markdown/MDX 正文。

页面布局用了统一的右侧栏结构。首页右边放作者说明、站内导航和最近更新,文章页放按时间和按主题浏览,分类页和项目页也各自有对应的辅助信息。移动端时右侧栏会自动落到正文下方。

全站还加了一个回到顶部按钮。页面往下滚动时按钮会出现,点一下就平滑返回顶部。这个功能很小,但对长文章会更顺手。

标签功能没有单独建数据库,也没有额外配置文件。页面直接从所有文章的 tags 字段中收集标签,生成 /tags/[tag]/ 页面。对个人博客来说,这样足够直接。

sitemap 使用 @astrojs/sitemap。在 astro.config.mjs 中配置 site 和 sitemap 集成后,构建时会生成站点地图。现在 site 已经配置为 https://cphxnotes.com

遇到的问题与解决方式

搭建过程中比较实际的问题出在依赖安装和 Node 版本上。Astro 升级到后面的 5.x 版本后,对 Node 版本要求更明确。如果还停在旧版本 Node,本地构建会直接被拦住。

最后的处理方式很直接:把 Astro 升到安全版本,同时把项目运行环境明确到 Node 20。这样本地和 Vercel 都按同一套版本走,后面排查问题也省事。

这也是为什么 package.json 里有 engines 字段,.nvmrc 里也写了 20。个人博客虽然简单,但依赖版本和运行时版本还是应该说清楚,尤其是准备部署到 Vercel 时。

另一个需要注意的点是站点 URL。sitemap 和 canonical URL 都依赖 site 配置。项目刚创建时还没有真实线上域名,所以先放占位值。后来买了 cphxnotes.com,就把站点地址统一改成 https://cphxnotes.com

本地运行方式

本地开发流程很简单:

nvm use 20
npm install
npm run dev

开发服务器启动后,打开终端输出的本地地址即可查看博客。

构建检查使用:

npm run build

构建产物会输出到 dist/

部署到 Vercel 的方式

最直接的方式是把项目推送到 GitHub,然后在 Vercel 新建项目并导入仓库。

Vercel 中保持默认 Astro 配置即可:

  • Framework Preset:Astro
  • Build Command:npm run build
  • Output Directory:dist
  • Install Command:npm install

部署到 Vercel 后,在项目的 Domains 里添加 cphxnotes.com,再按 Vercel 给出的记录去域名服务商那里配置 DNS。项目里的 astro.config.mjssrc/consts.ts 已经使用 https://cphxnotes.com,重新部署后 sitemap 和 canonical URL 会指向正式域名。

总结与后续可优化方向

这个版本先把博客的基础骨架搭稳:有首页、文章列表、文章详情、分类、项目、About、基础 SEO 和 sitemap。文章继续用 content collections 管理,后续新增内容只需要复制 Markdown 模板并修改 frontmatter。

后续可以继续优化的方向包括:

  • 增加 RSS
  • 增加评论或回复模块
  • 增加全文搜索
  • 增加更完整的项目页内容
  • 增加自定义 Open Graph 图片

目前最重要的事情是先把博客跑起来,并保持结构足够简单,方便长期写下去。