← 返回文章列表 专栏:前端与建站工程

更新于

Astro 静态博客工程搭建:目录结构、路由生成与构建校验流水线

使用 Astro 搭建零冗余静态技术博客,配置 Markdown 内容解析、固定永久链接、RSS 与本地搜索索引生成,以及自动化构建前检查。

Astro 静态构建流水线与构建期全量校验示意图
Astro 静态构建流水线与构建期全量校验示意图

静态站点生成器(SSG)的核心职责是将 Markdown 文稿与页面模板编译为标准 HTML、CSS 和 JSON 索引。相比在浏览器端动态请求接口渲染,预编译生成的静态页面首屏体积更小,也便于搜索引擎和 RSS 阅读器直接抓取。

本文记录基于 Astro 的静态博客工程目录划分、Markdown 渲染管线、atom.xml 与 search.json 生成逻辑,以及构建阶段的静态检查脚本。

工程目录划分与文件职责

初始化博客仓库(npm create astro@latest)时,建议将文章原稿、静态资源、页面组件和检查脚本按职责分开存放:

现代静态博客源码、构建检查与版本化生产托管边界图
开发与构建侧(左)负责 Markdown 内容管理、Astro 静态编译与构建期检查;编译生成的 public/ 经由 rsync 或 CI 交付至服务器 releases/ 版本目录(右),由 Nginx 容器只读挂载。
目录路径 职责说明 是否纳入 Git 是否进入生产 public/
source/_posts/ 存放 Markdown 技术文章(.md),包含 YAML Front Matter 是 仅 draft: false 且 published: true 的文章编译为 HTML 后进入
source/_data/ 存放结构化数据文件(如 projects.yml 开源项目清单、资源许可记录) 是 构建期由 TypeScript 读取渲染,原始 YAML 文件不直接暴露
static/ 存放无需编译的静态资源(images/、fonts/、robots.txt、favicon.svg) 是 构建时原样复制到 public/ 对应路径
src/ Astro 页面路由(pages/)、全局布局(layouts/)、组件(components/)与样式(styles/) 是 编译为静态 .html 与 .css
tools/ 与 docs/ 敏感信息扫描、标签词表、死链检查与插图完整性校验脚本 是 不进入公开 public/ 目录
public/ 最终静态构建产物目录(HTML/CSS/JS/SVG/WebP/XML/JSON) 否(加入 .gitignore) 同步至生产服务器 /srv/blog/releases/<版本号>/

核心构建配置:固定链接与目录索引输出

为了让编译生成的静态文件结构能够直接配合 Nginx 的目录索引分发,在项目根目录配置 astro.config.mjs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// astro.config.mjs — 静态博客构建配置
import { defineConfig } from 'astro/config';

export default defineConfig({
site: 'https://example.com', // 替换为实际博客域名
output: 'static',
publicDir: './static',
outDir: './public',
trailingSlash: 'ignore',
devToolbar: {
enabled: false
},
build: {
format: 'directory'
},
server: {
host: '0.0.0.0',
port: 3000
}
});

其中三个配置项直接影响线上路由行为:

  1. output: 'static' 与 build.format: 'directory': 动态路由 src/pages/posts/[slug].astro 会把 source/_posts/linux-systemd.md 编译为 public/posts/linux-systemd/index.html。访问 /posts/linux-systemd/ 时,Nginx 直接按目录索引返回 index.html,既保持了无 .html 后缀的干净 URL,又不需要编写额外的重写规则。
  2. publicDir: './static' 与 outDir: './public': 每次构建前先执行清理脚本(清空旧的 public/ 与 .astro/ 缓存),避免已删除或转为草稿的文章残留在输出目录中。
  3. devToolbar: { enabled: false }: 关闭开发模式下的浮动调试工具条,使本地预览画面与线上构建结果保持一致。

构建期内容解析、草稿隔离与静态索引生成

在 src/lib/content.ts 中编写统一的内容加载与渲染模块,在构建阶段完成以下处理:

1. 草稿过滤(Draft Isolation)

读取 source/_posts/*.md 时,仅允许 draft: false 且 published: true 的文章进入公开集合。未完成的草稿(draft: true)在构建期直接过滤,不会生成详情页 HTML,也不会出现在首页、归档、RSS 或搜索索引中。

2. 提取章节目录(TOC)与阅读时长估算

使用 Marked 自定义渲染器在编译期遍历 Markdown 语法树:

  • 为所有 <h2> 和 <h3> 标题生成锚点 id,并收集为 headings 数组供文章右侧目录组件渲染;
  • 为代码块生成带行号列(td.gutter)与代码列(td.code)的双列结构,并附上 data-lang 语言标识;
  • 根据中文字符数(按 300 字/分钟)与英文词数(按 200 词/分钟)在构建期估算每篇文章的阅读时长与总字数。

3. 生成 RSS、Sitemap 与本地搜索索引

在 src/pages/ 下通过三个静态端点脚本在构建期生成机器可读索引:

  • src/pages/atom.xml.ts → public/atom.xml:生成符合 RFC 4287 标准的 Atom 1.0 订阅源,包含最新 20 篇公开文章的标题、摘要、永久链接与 RFC 3339 时间戳;
  • src/pages/sitemap.xml.ts → public/sitemap.xml:枚举全站公开且非 noindex 的规范 URL,供搜索引擎抓取;
  • src/pages/search.json.ts → public/search.json:将公开文章的标题、分类、标签、摘要与纯文本正文导出为 JSON 索引,供前端本地全文检索按需加载。

本地开发、构建校验与远程版本同步

日常写作与发布主要使用以下三条命令:

1
2
3
4
5
6
7
8
# 1. 按 package-lock.json 安装依赖
npm ci

# 2. 启动本地开发预览服务(http://localhost:3000)
npm run dev

# 3. 执行生产构建并运行静态检查(清理 → 编译 → 标签/死链/敏感信息/锚点检查)
npm run check

当 npm run check 通过后,使用 rsync 将本地生成的 public/ 增量同步到服务器 /srv/blog/releases/ 下带时间戳的新版本目录中:

1
2
3
4
5
6
7
# 在本地或 CI 发布端执行:创建新版本目录并增量同步静态产物
RELEASE_ID="$(date -u +%Y%m%d-%H%M%S)"
ssh -p <新SSH端口> <管理用户名>@<服务器地址> "mkdir -p /srv/blog/releases/${RELEASE_ID}"

rsync -az --delete ./public/ \
-e "ssh -p <新SSH端口>" \
<管理用户名>@<服务器地址>:/srv/blog/releases/${RELEASE_ID}/

将产物同步到独立的 releases/${RELEASE_ID}/ 目录而非直接覆盖线上目录,主要有两点好处:

  • 避免传输过程中的文件不一致:直接覆盖线上目录时,若在 rsync 传输中途有请求进来,可能会同时读到新版 HTML 与尚未传完的旧版 CSS;
  • 便于快速回滚:上线后若发现排版或配置问题,将 /srv/blog/releases/current 软链接指回上一个时间戳目录即可恢复。

常见构建问题排查

故障现象 根因定位 处理方法
文章内引用的 SVG 或 WebP 图片显示 404 静态图片未放入 static/images/ 对应路径,或文件名大小写不一致 Linux 文件系统区分大小写,统一使用小写加连字符命名并运行 npm run check
将某篇文章改为 draft: true 后,public/posts/ 下仍存在对应 HTML 构建前未清空上一次生成的 public/ 目录 在 build 脚本前串联 clean 步骤清空 public/ 与 .astro/
RSS 阅读器报错 Invalid RFC3339 timestamp Front Matter 中的 date 或 updated 格式不规范 统一采用 YYYY-MM-DD HH:mm:ss 格式,由构建管线转换为 ISO 8601 / RFC 3339