博客快速发布_从0到1技术原理
博客快速发布 — 从 0 到 1 技术原理
如果你想手动完成这套发布系统,以下是每个环节的底层原理。
目录
- 整体架构
- Astro 静态站点生成原理
- Frontmatter 与 Content Collection
- gray-matter 库的工作原理
- Node.js 脚本编写原理
- Cloudflare Pages 部署原理
- Wrangler CLI 原理
- Git Hook 与 CI/CD
- 完整数据流
1. 整体架构
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐│ 用户写 .md │ ──▶ │ quick-publish │ ──▶ │ GitHub Repo │ ──▶ │ Cloudflare ││ (任意位置) │ │ 脚本处理 │ │ (main 分支) │ │ Pages │└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ (frontmatter、构建、git) │ ▼ ▼ ┌──────────────┐ ┌──────────────┐ │ dist/ 输出 │ ───────── 方案二 ──────▶ │ fzy.it.com │ └──────────────┘ (wrangler 直传) └──────────────┘两条路线:
- 路线 A(Git):md → frontmatter 补全 →
astro build→git push→ Cloudflare 自动构建部署 - 路线 B(直传):md → frontmatter 补全 →
astro build→wrangler pages deploy→ 直接上线
2. Astro 静态站点生成原理
什么是 SSG(Static Site Generator)
Astro 是一个静态站点生成器。它的核心工作方式是:
.md 文件 + .astro 模板 ──▶ astro build ──▶ 纯 HTML/CSS/JS 文件(dist/)与 WordPress 等动态 CMS 的区别:
| 动态 CMS (WordPress) | 静态站点 (Astro) | |
|---|---|---|
| 每次请求 | PHP 查询数据库 → 渲染 HTML | 直接返回预生成的 HTML |
| 存储 | 文章在 MySQL | 文章在 .md 文件 |
| 速度 | 需要服务器处理 | 极快(纯静态文件) |
| 部署 | 需要 PHP 服务器 | 任意静态文件服务器/CDN |
Astro 构建流程
当你运行 pnpm build(实际执行 astro build)时:
1. 扫描 src/content/posts/*.md2. 读取每个 .md 的 frontmatter3. 根据 Content Collection schema 校验4. 将 markdown 编译为 HTML5. 应用布局模板(.astro 文件)6. 生成完整的 HTML 页面7. 输出到 dist/ 目录8. pagefind 索引构建(搜索功能)关键配置(astro.config.mjs)
export default defineConfig({ site: "https://blog-astro.pages.dev", // 站点 URL base: "/", // 基础路径 trailingSlash: "always", // URL 末尾加 / // ...integrations});3. Frontmatter 与 Content Collection
什么是 Frontmatter
Frontmatter 是 markdown 文件顶部的 YAML 元数据块,用 --- 包裹:
---title: "我的文章标题"published: 2026-07-04description: "文章摘要"tags: [Python, 爬虫]category: "技术"draft: false---
这里是正文...为什么需要它
Astro 使用 Content Collections(内容集合)来管理文章。在 src/content.config.ts 中定义了 schema:
const postsCollection = defineCollection({ loader: glob({ pattern: "**/*.{md,mdx}", base: "./src/content/posts" }), schema: z.object({ title: z.string(), // 必须 published: z.date(), // 必须 draft: z.boolean().default(false), tags: z.array(z.string()).default([]), // ... }),});没有 frontmatter 或缺少必填字段 → 构建报错。 这就是为什么 quick-publish.js 要自动补全 frontmatter。
draft 字段的作用
draft: z.boolean().optional().default(false),draft: true→ 开发模式可见,生产构建不会生成该页面draft: false→ 正常发布
4. gray-matter 库的工作原理
安装
pnpm add gray-matter解析 frontmatter
import matter from "gray-matter";
const mdString = `---title: Hellotags: [a, b]---正文内容`;
const parsed = matter(mdString);console.log(parsed.data); // { title: "Hello", tags: ["a", "b"] }console.log(parsed.content); // "正文内容"生成带 frontmatter 的 markdown
const newMd = matter.stringify("新正文", { title: "New", published: "2026-07-04" });// 输出:// ---// title: New// published: '2026-07-04'// ---// 新正文底层原理
gray-matter 用正则表达式解析 --- 分隔符:
- 找到第一个
---和第二个---之间的内容 - 用 YAML 解析器(js-yaml)把这段文字转为 JavaScript 对象
- 第二个
---之后的部分作为正文 stringify时反向操作:JS 对象 → YAML 字符串 → 拼接---\nYAML\n---\n正文
5. Node.js 脚本编写原理
ESM 模块系统
脚本使用 ES Module("type": "module" 在 package.json 中):
import fs from "fs"; // 文件系统import path from "path"; // 路径处理import { execSync } from "child_process"; // 执行 shell 命令import matter from "gray-matter"; // frontmatter 解析execSync — 在 Node.js 中执行系统命令
import { execSync } from "child_process";
// 同步执行,输出到终端execSync("pnpm build", { stdio: "inherit" });
// stdio: "inherit" → 子进程的输出直接显示在当前终端// 不加的话,输出会被捕获到 buffer,用户看不到进度路径处理(跨平台兼容)
import path from "path";
path.resolve("src/content/posts"); // 相对路径 → 绝对路径path.join(dir, fileName); // 安全拼接路径(自动处理 / 和 \)path.basename("/a/b/c.md"); // "c.md"path.basename("/a/b/c.md", ".md"); // "c"path.extname("/a/b/c.md"); // ".md"process.argv — 获取命令行参数
// 命令: node script.js --new "Hello World" --no-draftprocess.argv // ["node", "script.js", "--new", "Hello World", "--no-draft"]process.argv.slice(2) // ["--new", "Hello World", "--no-draft"]6. Cloudflare Pages 部署原理
Cloudflare Pages 是什么
Cloudflare Pages 是 Cloudflare 的静态站点托管服务,类似于 Vercel/Netlify/GitHub Pages。它分布在全球 300+ 数据中心,用户访问时从最近的节点返回内容。
两种部署方式
方式 A:Git 集成(自动)
GitHub push ──▶ Cloudflare 检测到变更 ──▶ 自动执行构建命令 ──▶ 部署到全球 CDN配置步骤:
- Cloudflare Dashboard → Workers & Pages → 连接 Git 仓库
- 设置构建命令
pnpm build,输出目录dist - 每次 push 到 main 分支 → 自动触发
原理:Cloudflare 在你的 GitHub 仓库安装了一个 webhook,当有 push 事件时,GitHub 通知 Cloudflare,Cloudflare 拉取代码、在容器中执行构建、把产物分发到 CDN。
方式 B:Wrangler CLI 直传(手动)
本地 dist/ ──▶ wrangler pages deploy ──▶ Cloudflare API ──▶ 全球 CDN原理:跳过 Git,直接把本地构建产物通过 Cloudflare API 上传。Cloudflare 收到文件后分发到全球节点。
自定义域名原理
fzy.it.com ──(DNS CNAME)──▶ blog-astro.pages.dev ──▶ Cloudflare 边缘节点你在域名服务商处添加了一条 CNAME 记录,将 fzy.it.com 指向 Cloudflare Pages 分配的子域名。Cloudflare 自动配置 SSL 证书(通过 Let’s Encrypt 或 Cloudflare Origin CA)。
HTTP 响应头中的证据
Server: cloudflareCf-Cache-Status: DYNAMICCf-Cache-Status: DYNAMIC 表示该页面由 Cloudflare 动态回源(但 Astro 生成的静态 HTML 可以被缓存)。
7. Wrangler CLI 原理
安装
pnpm add -g wrangler # 全局安装# 或npx wrangler pages deploy dist --project-name=blog-astro # 临时使用身份认证
wrangler login这会打开浏览器,让你授权 Wrangler 访问你的 Cloudflare 账户。授权后,token 保存在本地(通常是 ~/.wrangler/config/default.toml),后续请求携带此 token。
部署命令
npx wrangler pages deploy dist --project-name=blog-astro --branch=main实际做的事情:
- 读取
dist/目录下所有文件 - 计算文件哈希(用于增量上传,只传变更文件)
- 通过 Cloudflare API 上传文件
- Cloudflare 验证文件完整性
- 分发到全球 CDN 节点
- 返回部署 URL
wrangler.toml 配置文件
name = "blog-astro"compatibility_date = "2026-05-30"
[pages]output_dir = "dist"build_command = "pnpm run build"这个文件告诉 Wrangler 项目的元信息,Cloudflare Dashboard 也会读取它来配置自动构建。
8. Git Hook 与 CI/CD
当前 GitHub Actions 工作流
项目中有 .github/workflows/deploy.yml:
on: push: branches: [main]
jobs: build-and-deploy: steps: - checkout # 拉取代码 - setup pnpm/node # 安装环境 - pnpm build # 构建 - deploy to pages # 部署到 pages 分支(GitHub Pages)GitHub Actions 原理
- GitHub 仓库根目录下的
.github/workflows/*.yml被 GitHub 自动识别 - 当触发条件满足(如 push 到 main),GitHub 分配一台虚拟机(runner)
- Runner 按 steps 逐步执行
- 每个 step 要么是一个 shell 命令,要么是一个现成的 action(如
actions/checkout@v4)
你实际用的是 Cloudflare Pages Git 集成
虽然 deploy.yml 部署到了 GitHub Pages 的 pages 分支,但你的域名 fzy.it.com 实际指向的是 Cloudflare Pages。这说明你配置了 Cloudflare Pages 的 Git 集成:
Git push main → Cloudflare 自动检测 → 在自己的容器中构建 → 部署到 CDN这比 GitHub Actions 更简洁,因为:
- 不需要维护 workflow 文件
- 构建在 Cloudflare 的全球网络中进行
- 部署和 CDN 是同一个平台,分发更快
9. 完整数据流
以一个外部 md 文件为例,追踪完整过程:
1. 用户执行: pnpm publish "E:\notes\Python协程.md"
2. quick-publish.js 执行: ┌─ 解析命令行参数 ├─ fs.readFileSync("E:\notes\Python协程.md") ├─ matter(mdString) → 解析 frontmatter │ ├─ 有 title + published? → 跳过 │ └─ 没有? → 自动生成 frontmatter → 写回文件 ├─ fs.copyFileSync() → 复制到 src/content/posts/ ├─ execSync("pnpm build") │ ├─ node scripts/generate-icons.js (图标生成) │ ├─ astro build │ │ ├─ 扫描 src/content/posts/*.md │ │ ├─ 校验 frontmatter schema │ │ ├─ Markdown → HTML (remark + rehype 插件) │ │ │ ├─ remark-math (数学公式) │ │ │ ├─ rehype-katex (KaTeX 渲染) │ │ │ ├─ remark-mermaid (Mermaid 图表) │ │ │ ├─ rehype-autolink-headings (标题锚点) │ │ │ └─ ... 其他插件 │ │ ├─ 应用布局模板 .astro │ │ └─ 输出到 dist/ │ └─ pagefind --site dist (搜索索引) ├─ execSync("git add .") ├─ execSync("git commit -m 'publish: Python协程.md'") └─ execSync("git push origin main")
3. GitHub 接收到 push → 触发 Cloudflare webhook
4. Cloudflare Pages: ├─ 拉取 main 分支最新代码 ├─ 在容器中执行 pnpm install + pnpm build └─ 分发 dist/ 到全球 CDN
5. 用户访问 https://fzy.it.com → Cloudflare 边缘节点 → 返回 HTML关键概念速查
| 概念 | 一句话解释 |
|---|---|
| SSG | 构建时生成 HTML,不需要服务器 |
| Frontmatter | md 文件顶部的 YAML 元数据 |
| Content Collection | Astro 对 md 文件的类型化管理 |
| gray-matter | 解析/生成 frontmatter 的 npm 包 |
| execSync | Node.js 中同步执行系统命令 |
| Cloudflare Pages | CDN 静态站点托管 |
| Wrangler | Cloudflare 命令行工具 |
| CNAME | 域名别名记录(fzy.it.com → pages.dev) |
| Webhook | Git 事件触发远程服务的机制 |
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!