系列 · 从零搭博客 · 第 1 篇 (系列目录)
用 Astro 5 + TypeScript 从零搭建一个博客
约 5 分钟
这篇文章记录这套博客的骨架搭建过程。选 Astro 的理由很直接:内容优先、默认零 JS、原生 TypeScript,而且它的 View Transitions 让页面转场动画变得非常顺滑。
1. 初始化项目
npm create astro@latest my-blog -- --template minimal --typescript strict
cd my-blog
npx astro add tailwind
2. 用内容集合管理文章
Astro 5 的 Content Collections 让 Markdown 的 frontmatter 获得完整的类型校验。在 src/content.config.ts 里定义 schema:
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: '**/[^_]*.md', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});
export const collections = { blog };
从此以后,frontmatter 少写一个字段、日期格式写错,构建时都会直接报错——这对博客这种「内容即数据」的项目太重要了。
3. 列表页拿数据
---
import { getCollection } from 'astro:content';
// draft: true 的草稿不会发布
const posts = await getCollection('blog', ({ data }) => !data.draft);
---
{posts.map((post) => <a href={`/blog/${post.id}/`}>{post.data.title}</a>)}
post.id 默认就是文件名,所以 hello-world.md 会生成 /blog/hello-world/。
4. 双主题代码高亮
在 astro.config.mjs 里配置 Shiki 的双主题,亮暗两套配色一次性输出:
export default defineConfig({
markdown: {
shikiConfig: {
themes: {
light: 'github-light',
dark: 'one-dark-pro',
},
},
},
});
Shiki 会把暗色配色写进每个 span 的 --shiki-dark 变量,配合几行 CSS 就能在切换主题时零延迟变色:
[data-theme='dark'] .astro-code,
[data-theme='dark'] .astro-code span {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
}
5. 搜索、评论、RSS
- 搜索:pagefind 在构建后对
dist建立纯前端索引,不需要任何服务端 - 评论:giscus 复用仓库的 GitHub Discussions,数据在自己手里
- RSS:
@astrojs/rss一个 GET 端点搞定
6. 部署
GitHub Actions 监听 main 分支推送 → 构建 → 发布到 Pages。核心就是官方的 withastro/action:
- uses: withastro/action@v3
- uses: actions/upload-pages-artifact@v3
with:
path: dist
踩坑记录
- base 路径:GitHub Pages 项目站点部署在
/blog/子路径,所有内部链接必须拼接 base,否则线上全 404。解决方式是统一封装withBase()函数 - 换页后主题闪烁:View Transitions 会用新页面的
<html>覆盖当前属性,主题初始化脚本必须加data-astro-rerun让它每次换页重新执行 - 中文字体:完整的中文 webfont 动辄好几 MB,直接用系统字体栈反而最快最稳
总结
Astro 的「内容优先」哲学和博客场景完美匹配:页面默认零 JS、内容有类型校验、动效有官方转场方案。剩下的事,就只剩好好写文章了。