最近又折腾了一遍博客——也就是你现在看到的 Hexvork(hexvork.com)。
从 Hexo、Halo,到最终回到 Astro,越来越觉得这玩意儿像是为个人博客量身定做的。快、轻、现代,开发体验很舒服。尤其是 AI Coding 爆发之后,Astro + Trae IDE / Cursor 这套组合,已经不是”写博客”了,是在搭一个真正属于自己的内容网站。
这篇文章以我自己的 Hexvork 博客为例,从 pnpm 安装、Astro 初始化、AI 辅助开发,一路走到部署上线。
为什么选 Astro
传统方案有点重了。Hexo 生态成熟但主题老旧,VitePress 偏文档,Next.js 像做企业项目。
Astro 的感觉是:把静态博客重新做了一遍现代化设计。
默认极致静态化、极少 JS、岛屿架构、SEO 友好、原生 Markdown 支持,页面速度极快。Hexvork 博客基于 MD3 Token 体系 + TailwindCSS 搭了整套暗色/亮色主题,配合自建图床 img.hexvork.com,视觉一致性很高。
一、装 pnpm
pnpm 基本是前端新标准了,快、省空间、依赖结构干净。
npm install -g pnpm
pnpm -v
输出版本号就装好了。
二、创建项目
pnpm create astro@latest
CLI 会问项目名,我用的 astro-blog。建议选:不要样板文件、装依赖、初始化 git。
cd astro-blog
pnpm dev
localhost:4321 出来就成功了。
三、常用命令
日常就四个命令,都是 pnpm 标准用法:
pnpm dev # 开发服务器,热更新
pnpm astro check # 类型检查,校验 frontmatter
pnpm build # 生产构建,输出到 dist/
pnpm preview # 本地预览构建结果
工作流:dev 开发 → check 验类型 → build 构建 → preview 预览 → push 上线。
四、Astro 强在哪
第一次用 Astro 的感觉:这东西怎么这么干净?
没有 useEffect 地狱、客户端 JS 爆炸、hydration 泛滥。核心理念就一句话——能静态,就静态。
---
const title = "Hello Astro"
---
<h1>{title}</h1>
没有运行时,直接输出 HTML。Lighthouse 分数想低都难。
五、接入 AI
重点来了。真正离谱的不是 Astro,是 Astro + AI Coding。我第一次感受到:一个人真的像一个开发团队。
AGENTS.md
不用 .cursorrules,项目根目录放 AGENTS.md,Trae IDE、Cursor 都能自动读。我的大概是这个样子:
# AGENTS.md — Hexvork Blog
## 命令
| 命令 | 说明 |
|------|------|
| `pnpm dev` | 启动开发服务器 |
| `pnpm build` | 类型检查 + 构建 |
## 技术栈
- Astro 6.x(output: 'static')
- TailwindCSS 3.4 + MD3 Token 体系
- astro:content collections
- 域名: hexvork.com / 图床: img.hexvork.com
## CSS 注意
- backdrop-filter 不能放 transform 动画祖先下
- a::after 有蓝色下划线,自定义链接需排除
- 暗色模式: .dark 类 + CSS 变量
有了它,AI 就不会乱改毛玻璃、加回全局下划线。你按自己的域名、图床改改就能用。
项目结构
折腾半年,Hexvork 最终稳定成这样:
astro-blog/
├── src/
│ ├── content/posts/ # 所有文章
│ ├── layouts/MainLayout.astro
│ ├── components/ # Header、Giscus、卡片等
│ ├── pages/ # 首页、文章详情、工具页、留言板
│ ├── styles/
│ │ ├── global.css # MD3 Token + 全局
│ │ └── tech-enhancements.css
│ └── config.ts # 站点配置一把抓
├── public/
└── astro.config.mjs
好处:文章和配置各回各家、组件拆得够细、样式分层不打架。结构越清晰,AI 越不容易写出屎山。
六、Tailwind + MD3
pnpm astro add tailwind
一路 Yes。Hexvork 还搭了 MD3 Token 体系——颜色、阴影、圆角全用 CSS 变量(--md-primary、--md-surface 等),暗色模式 .dark 类切换,不硬编码颜色。
七、Content Collections
我愿称之为”防呆设计”——给 Markdown frontmatter 加类型校验,写错构建直接炸。
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const postsCollection = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
date: z.date(),
abbrlink: z.string(),
description: z.string(),
tags: z.array(z.string()),
categories: z.string(),
}),
});
export const collections = { 'posts': postsCollection };
写文章时 date 填了字符串而不是日期,pnpm build 当场报错。比上线后 debug 舒服一万倍。
核心页面
首页——捞文章、排序、渲染:
---
import { getCollection } from 'astro:content';
const allPosts = (await getCollection('posts'))
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
---
<main>
{allPosts.map(post => (
<Card title={post.data.title} slug={post.data.abbrlink} />
))}
</main>
文章详情——getStaticPaths() 构建时生成全部路由,输出纯静态 HTML:
---
export async function getStaticPaths() {
const posts = await getCollection('posts');
return posts.map(post => ({
params: { slug: post.data.abbrlink }, props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await post.render();
---
<article>
<h1>{post.data.title}</h1>
<Content />
</article>
标签页——自动聚合,每个标签一个静态页面:
---
export async function getStaticPaths() {
const allPosts = await getCollection('posts');
const tags = [...new Set(allPosts.flatMap(p => p.data.tags))];
return tags.map(tag => ({
params: { tag },
props: { posts: allPosts.filter(p => p.data.tags.includes(tag)) },
}));
}
---
三个页面全部构建时静态化,零运行时查询。
八、锦上添花
搜索:我直接前端拉 RSS XML,浏览器里本地过滤。零依赖,天然和 RSS 同步,标题/描述/时间/全文四个维度随便切。
RSS:@astrojs/rss 几行配置出 /rss.xml,读者订阅不用刷网站。
暗色模式:MD3 Token 体系下亮色/暗色各一套变量,.dark 类切换,localStorage 记状态。
代码高亮:Astro 内置 Shiki,配个主题,100+ 语言。
评论:Giscus,基于 GitHub Discussions,数据在自己仓库。
九、部署
pnpm astro check && pnpm build && pnpm preview
确认没问题,push。Hexvork 跑在 Cloudflare Pages,开了 CDN。Vercel、Netlify 也一样,GitHub 连上就自动部署。
最后
以前做博客像维护系统,现在像创造自己的数字空间。
Hexvork 从 Hexo 迁到 Astro,全程 AI 辅助,比想象中顺畅太多。Astro 是我觉得最适合个人博客现代化的方案,配合 AI,一个人真的能做出比团队还快的网站。