Daimon's Blog
主页 归档 关于 RSS 探针 常用工具
主页
归档
关于
RSS
探针
常用工具

Astro + Fuwari 博客搭建:从主题到个人化改造

daimon daimon 2025-04-28 #Astro#Fuwari#博客#Giscus#APlayer#前端

搭个人博客最容易卡住的地方不是「能不能跑起来」,而是跑起来之后不像自己的东西——首页还是模板味,文章卡片没有记忆点,详情页信息太杂,评论和音乐播放器又散落在各种教程里。

这篇按我当前博客的实际结构写:先用 Astro + Fuwari 搭出基础,再逐步接入音乐播放器、Giscus 评论、首页 Hero 改造、文章列表卡片、文章详情页布局和部署检查。目标不是复刻原主题,而是把它改成适合长期写技术笔记的个人站。

一、整体方案#

当前博客的核心是:

模块选择作用
静态框架Astro生成静态页面,适合部署到 EdgeOne Pages、Cloudflare Pages、Vercel
主题基础Fuwari提供文章系统、归档、RSS、Markdown 渲染、目录、明暗主题
样式体系Tailwind CSS + Stylus快速写布局,统一主题变量
页面切换Swup页面过渡和局部更新
评论Giscus使用 GitHub Discussions 做评论区
音乐APlayer + Meting底部悬浮播放器
搜索Pagefind构建后生成本地搜索索引

为什么不从零写主题?

方案优点问题
从零写 Astro 博客结构完全可控文章集合、RSS、分页、目录、Markdown 插件都要自己补
直接用 Fuwari功能完整首页和文章页模板味比较重
在 Fuwari 上改保留成熟功能,同时改视觉需要读懂布局和组件之间的关系

这里走第三种:保留 Fuwari 的内容系统,重写关键视觉层。

二、初始化 Astro + Fuwari#

如果是新项目,可以直接用 Fuwari 模板初始化;如果已经有仓库,就拉下来安装依赖。

Terminal window
1
pnpm install

本地启动:

Terminal window
1
pnpm run dev

构建:

Terminal window
1
pnpm run build

预览构建结果:

Terminal window
1
pnpm run preview

当前项目的核心命令在 package.json:

1
{
2
"scripts": {
3
"dev": "astro dev",
4
"check": "astro check",
5
"build": "astro build && pagefind --site dist",
6
"preview": "astro preview",
7
"new-post": "node scripts/new-post.js",
8
"format": "biome format --write ./src",
9
"lint": "biome check --write ./src"
10
}
11
}

构建命令后面接了 pagefind --site dist,意思是 Astro 先生成静态站点,再给 dist 目录建立搜索索引。

三、先改全站配置#

站点基础配置集中在:

1
src/config.ts

这里改站点标题、语言、主题色、导航、头像、社交链接:

1
export const siteConfig = {
2
title: "Daimon's Blog",
3
subtitle: "在折腾中生活,在探索中成长",
4
lang: "zh_CN",
5
themeColor: {
6
hue: 105,
7
fixed: false,
8
},
9
};

hue 是主题色相,范围是 0-360。例如:

色相大致颜色
0红色
60黄色
105偏绿色
200青色
240蓝色
270紫色
330粉色

导航也在同一个文件里:

1
export const navBarConfig = {
2
links: [
3
LinkPreset.Home,
4
LinkPreset.Archive,
5
LinkPreset.About,
6
{
7
name: "常用工具",
8
url: "https://webtools.example.com/",
9
external: true,
10
icon: "fa6-solid:screwdriver-wrench",
11
},
12
],
13
};

只改导航文字、链接、图标时,优先改 src/config.ts。只有要改 Dock 外观时,才去动 src/components/Navbar.astro。

四、整理目录结构#

日常真正高频修改的是这些位置:

路径作用
src/content/posts/博客文章
src/content/spec/about.md关于页
src/config.ts站点配置、导航、头像、社交链接
PicList + 七牛云头像、轮播图、文章封面
src/assets/images/迁移前原图备份
src/components/misc/HeroSection.astro首页 Hero
src/components/PostCard.astro首页文章卡片
src/pages/posts/[...slug].astro文章详情页
src/components/misc/Giscus.astro评论系统
src/components/FloatingMusicPlayer.astro音乐播放器
src/layouts/MainGridLayout.astro全站布局骨架
src/styles/markdown.cssMarkdown 正文样式
src/styles/variables.styl全站颜色变量

生成目录不要手动改:

1
dist/
2
.astro/
3
node_modules/

这些目录会由构建工具生成。手动改了也不会成为真正的源码。

五、写文章和封面#

文章放在:

1
src/content/posts/

可以用脚本新建:

Terminal window
1
pnpm run new-post my-note

也可以直接写 Markdown。Frontmatter 示例:

1
---
2
title: Astro + Fuwari 博客搭建:从主题到个人化改造
3
published: 2025-04-28
4
description: 记录从 Astro + Fuwari 初始化个人博客,到接入音乐播放器、Giscus 评论、首页 Hero、文章卡片、详情页布局、部署检查的完整改造流程。
5
image: http://imagebed.daimona.cn/astro-fuwari-blog-guide.png
6
tags: ["Astro", "Fuwari", "博客", "Giscus", "APlayer", "前端"]
7
category: 博客
8
---

封面图通过 PicList 上传到七牛云:

1
https://imagebed.daimona.cn

上传成功后,把完整 URL 写入 Frontmatter:

1
image: http://imagebed.daimona.cn/<slug>.png

首页文章卡片使用 16:9 比例,推荐封面尺寸:

尺寸说明
1280x720最低建议
1600x900推荐
1920x1080更清晰,适合后续复用

图片会使用 object-fit: cover 裁切,所以重要内容不要贴边。

六、接入音乐播放器#

音乐播放器组件在:

1
src/components/FloatingMusicPlayer.astro

当前使用 APlayer + Meting:

1
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css">
2
<script is:inline src="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script>
3
<script is:inline src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>
4
5
<meting-js
6
server="netease"
7
type="playlist"
8
id="17997617137"
9
fixed="true"
10
mini="true"
11
order="random"
12
loop="all"
13
volume="0.7"
14
lrc-type="1">
15
</meting-js>

常改参数:

参数作用示例
server音乐平台netease
type类型playlist、song、album
id歌单或歌曲 ID17997617137
fixed固定在页面底部true
mini迷你模式true
order播放顺序random
loop循环方式all
volume默认音量0.7

组件在全站布局里挂载:

1
<FloatingMusicPlayer />

位置在:

1
src/layouts/Layout.astro

这样所有页面都会显示播放器,不需要每个页面单独引入。

七、接入 Giscus 评论#

评论组件在:

1
src/components/misc/Giscus.astro

配置集中成一个对象:

1
const giscusConfig = {
2
repo: "daimon3332/Giscus-daimin-blog",
3
repoId: "R_kgDOSqHPHA",
4
category: "Announcements",
5
categoryId: "DIC_kwDOSqHPHM4C-ABX",
6
mapping: "pathname",
7
strict: "0",
8
reactionsEnabled: "1",
9
emitMetadata: "0",
10
inputPosition: "bottom",
11
theme: "preferred_color_scheme",
12
lang: "zh-CN",
13
};

Giscus 的核心是 GitHub Discussions:

字段说明
repo用来存评论的 GitHub 仓库
repoId仓库 ID
categoryDiscussions 分类名
categoryId分类 ID
mapping页面和讨论的映射方式
theme评论区主题
lang评论区语言

文章详情页里直接引入:

1
import Giscus from "@components/misc/Giscus.astro";
2
3
<Giscus />

当前项目把评论放在正文后面,路径是:

1
src/pages/posts/[...slug].astro

这样每篇文章都有独立评论区,映射方式用 pathname,URL 不变时评论就不会丢。

八、改首页 Hero#

首页 Hero 组件在:

1
src/components/misc/HeroSection.astro

它做了几件事:

功能实现位置
背景轮播heroSlides 保存七牛云 URL
花瓣飘落.petal-layer 和 @keyframes petal-fall
圆形头像profileConfig.avatar
打字机文案.typewriter
GitHub 链接profileConfig.links
个人标签personalTags

轮播图配置:

1
const heroSlides = [
2
"http://imagebed.daimona.cn/terminal-bg.webp",
3
"http://imagebed.daimona.cn/wallhaven-9o2km8.webp",
4
];

轮播切换参数:

1
const carouselInterval = 3000;
2
const fadeDuration = 1200;
3
const zoomDuration = 4200;

打字机文字:

1
const emoText = "有些人像黄昏,来时温柔,去时荒凉";

个人标签:

1
const personalTags = [
2
{ label: "VPS 驯兽师", href: "/archive/" },
3
{ label: "逆向爱好者", href: "/archive/" },
4
{ label: "服务器炼金术士", href: "/archive/" },
5
{ label: "NixOS 信徒", href: "/archive/" },
6
{ label: "Root 玩家", href: "/archive/" },
7
{ label: "终端效率洁癖", href: "/archive/" },
8
];

这里的设计原则是:首页只负责建立气质,不负责塞满信息。文章列表往下滚就能看到,Hero 区只保留头像、文案、个人入口和几个关键词。

九、改文章卡片#

首页文章卡片在:

1
src/components/PostCard.astro

当前卡片结构是:

1
<article class:list={["note-card", className]} style={style}>
2
<a href={url} class="note-link" aria-label={title}>
3
<div class="note-cover-wrap">
4
<ImageWrapper class="note-cover" />
5
</div>
6
7
<div class="note-body">
8
<h2>{title}</h2>
9
<p>{description}</p>
10
<div class="note-meta-row">
11
<time>{published}</time>
12
<span class="word-count">字数</span>
13
<span class="note-tags">标签</span>
14
</div>
15
</div>
16
</a>
17
</article>

封面比例由 CSS 控制:

1
.note-cover-wrap {
2
width: 100%;
3
aspect-ratio: 16 / 9;
4
overflow: hidden;
5
background: #07080d;
6
}
7
8
.note-cover img {
9
width: 100%;
10
height: 100%;
11
object-fit: cover;
12
}

卡片只保留这些信息:

信息保留原因
封面建立视觉记忆
标题文章入口
摘要帮读者判断内容
日期判断新旧
字数判断阅读成本
标签判断主题

分类没有放在卡片里,因为标签已经足够表达主题。分类适合归档统计,不适合每张卡片都展示。

十、改文章详情页#

文章详情页在:

1
src/pages/posts/[...slug].astro

当前顶部只保留:

元素说明
标题页面核心
头像作者识别
作者名个人博客标识
日期发布时间
标签当前文章主题

结构大致是:

1
<header class="post-header">
2
<h1>{entry.data.title}</h1>
3
4
<div class="post-author-line">
5
<img src={profileConfig.avatar || ""} alt={profileConfig.name} />
6
<span>{profileConfig.name}</span>
7
<time>{formatDateToYYYYMMDD(entry.data.published)}</time>
8
<span class="post-tags">
9
{entry.data.tags.map((tag) => <span class="post-tag">#{tag}</span>)}
10
</span>
11
</div>
12
</header>
13
14
<Markdown>
15
<Content />
16
</Markdown>
17
18
<Giscus />

删掉了这些默认信息:

被删内容原因
PV 次数当前没有稳定统计系统,先不放
文章地址复制块对个人博客正文干扰大
作者信息大卡片顶部头像已经够了
许可协议块页脚和站点说明已经覆盖

正文宽度由 MainGridLayout.astro 控制:

1
isPostPage
2
? "grid grid-cols-1 xl:grid-cols-[1fr_minmax(0,64rem)_16rem] 2xl:grid-cols-[1fr_minmax(0,70rem)_17rem]"
3
: "grid grid-cols-1"

也就是:

1
左侧空白 / 中间正文 / 右侧目录

中间正文最大宽度在大屏下是 64rem 到 70rem,比原主题更宽,适合长教程。

十一、保留右侧目录#

目录逻辑在:

1
src/layouts/MainGridLayout.astro
2
src/components/widget/TOC.astro

只在文章页显示:

1
{siteConfig.toc.enable && isPostPage && (
2
<div id="toc-wrapper">
3
<TOC headings={headings}></TOC>
4
</div>
5
)}

开关在 src/config.ts:

1
toc: {
2
enable: true,
3
depth: 3,
4
}

长教程必须保留目录。技术文章动不动几千字,没有目录就很难回到某个小节。

十二、改全站布局#

布局核心在:

1
src/layouts/MainGridLayout.astro

当前首页和文章页走不同布局:

页面布局
首页单列内容,顶部 Hero
文章页中间正文 + 右侧目录
关于页 / 归档页普通内容布局

判断文章页:

1
const isPostPage = Astro.url.pathname.startsWith(url("/posts/"));

首页是否显示 Hero:

1
const isHomePage = pathsEqual(Astro.url.pathname, url("/"));
2
const showHomeBanner = siteConfig.banner.enable && isHomePage;

页面最大宽度在:

1
src/constants/constants.ts
1
export const PAGE_WIDTH = 96;

首页每页文章数量也在这里:

1
export const PAGE_SIZE = 8;

这些属于「常改但不要乱改」的参数。宽度改太大,正文阅读会散;每页文章太多,首页加载和浏览节奏都会变差。

十三、接入部署检查#

每次改完先跑:

Terminal window
1
pnpm run check
2
pnpm run build

EdgeOne Pages 这类静态托管平台通常填:

1
构建命令:pnpm run build
2
输出目录:dist
3
包管理器:pnpm

推送流程:

Terminal window
1
git status
2
git add .
3
git commit -m "更新博客"
4
git push

如果平台已经绑定仓库,git push 后会自动构建。

十四、常见故障速查#

现象原因处理
首页封面不显示图床 URL 写错检查 URL 能否直接访问
本地正常,线上图片失败图床防盗链配置错误检查博客域名是否在 Referer 白名单
Giscus 不显示仓库或分类 ID 错重新到 giscus.app 生成配置
评论每篇文章串在一起mapping 配错个人博客建议用 pathname
音乐播放器没出现CDN 被拦或脚本未加载检查浏览器 Network 和 Console
TOC 点击不跳转标题 slug 或 Swup 容器问题检查 rehype-slug 和 #toc 容器
构建后搜索无结果Pagefind 没跑确认 build 命令包含 pagefind --site dist

构建时看到这些不一定是错误:

1
Pagefind doesn't support stemming for the language zh-cn.

意思是中文没有英文那种词根匹配,搜索仍然可用。

1
Browserslist: browsers data (caniuse-lite) is old.

意思是浏览器兼容性数据库旧了,不会直接导致构建失败。

十五、几条实用经验#

  • 先改配置,再改组件:标题、导航、头像、链接都在 src/config.ts,不要一开始就钻组件。
  • 首页只负责气质:轮播图、头像、emo 文案、个人标签够了,不要把所有功能都塞进首屏。
  • 文章卡片不要展示太多字段:标题、摘要、日期、字数、标签已经足够。
  • 详情页顶部要克制:技术教程读者是来看内容的,不是看一堆元信息。
  • 评论单独做组件:以后从 Giscus 换到别的系统,只改 Giscus.astro 和详情页引用。
  • 音乐播放器全站挂载:放在 Layout.astro,不要每个页面重复引。
  • 所有常改点加标记:代码里用 ★ 常改 标出来,几个月后回来还能快速找到入口。
  • 写新教程前先看规范:src/content/posts/tutorial-style-guide.md 是文章风格基准,标题、表格、代码块、结尾都按它来。
教程写作风格规范
本博客所有文章除特别声明外,均遵循 CC BY-NC-SA 4.0 协议,转载请注明出处。
博客框架 Astro & Fuwari
冀ICP备20260167号
1
一、整体方案
2
二、初始化 Astro + Fuwari
3
三、先改全站配置
4
四、整理目录结构
5
五、写文章和封面
6
六、接入音乐播放器
7
七、接入 Giscus 评论
8
八、改首页 Hero
9
九、改文章卡片
10
十、改文章详情页
11
十一、保留右侧目录
12
十二、改全站布局
13
十三、接入部署检查
14
十四、常见故障速查
15
十五、几条实用经验