视频加载失败

Firefly 博客接入友链朋友圈:从零开始的完整部署教程

6745 字
34 分钟
Firefly 博客接入友链朋友圈:从零开始的完整部署教程
Firefly 博客接入友链朋友圈:从零开始的完整部署教程

Firefly 博客接入「友链朋友圈」完整部署教程#

适用对象:基于 Firefly(Astro) 主题的静态博客 + Friend-Circle-Lite(下称 FCL)友圈数据服务。 本文是实战复盘:每一步、每一处代码改动都来自真实部署过程,照做即可从零跑通。 预计耗时:1~2 小时。难度:会复制粘贴、会用命令行敲几条命令即可(文中有兜底的网页操作替代方案)。


0. 先搞懂原理:三个部分怎么协作#

友链朋友圈不是”装进博客的插件”,而是一条独立的数据流水线:

┌────────────────────────────┐
│ ① 你的博客仓库 │ 展示层
│ Firefly (Astro) │ /fcircle/ 页面
│ 每次构建生成 friend.json ───┼──┐ (你的友链名单)
└────────────────────────────┘ │
▼
┌────────────────────────────┐ 每 4 小时爬一次
│ ② 你的 FCL fork 仓库 │◄─┘ 读取 friend.json
│ GitHub Actions 定时爬虫 │──► 抓取每个友链的 RSS
│ 产出 all.json / link.json │──► 推送到 page 分支
└──────────────┬─────────────┘
│ git push (自动)
▼
┌────────────────────────────┐
│ ③ Vercel 数据站 │ 托管层
│ 托管 page 分支的静态文件 │ https://fc.你的域名/
│ 提供 all.json (带 CORS 头) │
└──────────────┬─────────────┘
│ fetch 跨域读取
▼
/fcircle/ 页面渲染友圈文章流

职责划分:

部分负责什么技术栈
① 博客仓库新增 /fcircle/ 页面;构建时生成友链名单 friend.jsonAstro + Firefly 主题
② FCL fork 仓库每 4 小时定时爬取友链 RSS,生成数据文件Python + GitHub Actions(免费)
③ Vercel把数据文件托管成 HTTPS 静态站(带 CORS 头)Vercel 免费版

最终效果:博客上出现「友圈」菜单和 /fcircle/ 页面,自动聚合所有友链的最新文章,每 4 小时更新一次,全程无需人工干预。


1. 准备工作#

开始前确认你有:

  1. GitHub 账号 —— 托管博客仓库和 FCL fork
  2. Vercel 账号 —— 免费版即可(vercel.com 注册,可用 GitHub 登录)
  3. Cloudflare 账号 + 你自己的域名 —— 博客已解析在 Cloudflare 上(本文以 mstzuomu.space 为例,换成你自己的)

    国内访问者无法解析 *.vercel.app(被 DNS 污染),必须绑自定义域名,否则访客拉不到数据。

  4. 本机环境:
    • Node.js ≥ 22、pnpm ≥ 11(你跑得动 pnpm dev 就说明够了)
    • Git 基本操作(add / commit / push)
    • 浏览器

命令行注意(Windows):教程里的 curl 命令请写成 curl.exe。PowerShell 里裸写 curl 会别名到 Invoke-WebRequest,参数不兼容会报错。


2. 第一部分:博客侧代码改造#

改动清单(共 10 处,先看全貌再逐个做):

#文件操作作用
2.1scripts/generate-friend-json.ts新增从友链配置生成 FCL 需要的 friend.json
2.2package.json修改把生成脚本挂进 pnpm build
2.3public/friend.json生成执行脚本产出(会被发布到站点根目录)
2.4src/config/fcircleConfig.ts新增友圈页面配置(数据站地址等)
2.5src/config/index.ts修改导出新配置
2.6src/pages/fcircle.astro新增友圈页面本体
2.7src/types/siteConfig.ts + src/config/siteConfig.ts修改页面开关 pages.fcircle
2.8src/config/navBarConfig.ts修改导航栏「社交 → 友圈」菜单
2.9public/fclite/fclite.js、fclite.css新增FCL 前端渲染脚本(自托管 + 按 2.9 做主题化改造)
2.10—验证本地跑通 → 提交推送 → 线上验证

2.1 新增 scripts/generate-friend-json.ts#

FCL 的爬虫只认一种友链格式:{"friends": [["站点名", "网址", "头像"], ...]}。Firefly 的友链写在 src/config/friendsConfig.ts 里,所以需要一个脚本做转换。

新建文件,完整内容:

import fs from "node:fs/promises";
import path from "node:path";
import { getEnabledFriends } from "../src/config/friendsConfig";
// 生成 Friend-Circle-Lite 所需的友链数据文件
// 格式: { "friends": [["站点名", "站点地址", "头像地址"], ...] }
// 产物发布到站点根目录 (public/friend.json),供 FCL 的 Action 定时拉取
const OUTPUT_FILE = path.join("public", "friend.json");
async function main() {
const friends = getEnabledFriends();
const data = {
friends: friends.map((item) => [item.title, item.siteurl, item.imgurl]),
};
await fs.mkdir(path.dirname(OUTPUT_FILE), { recursive: true });
await fs.writeFile(OUTPUT_FILE, `${JSON.stringify(data, null, 2)}\n`, "utf-8");
console.log(`friend.json 已生成: ${OUTPUT_FILE} (${friends.length} 个友链)`);
}
main().catch((error) => {
console.error("生成 friend.json 失败:", error);
process.exit(1);
});

它只导出 enabled: true 的友链,与 /friends/ 页面看到的列表保持一致。以后你增删友链,只要正常改 friendsConfig.ts,其余全自动。

2.2 修改 package.json#

打开 package.json 的 scripts,做两处修改:

改动 1:build 命令最前面插入生成步骤:

"build": "npx tsx scripts/generate-github-card-data.ts && ..."
"build": "npx tsx scripts/generate-friend-json.ts && npx tsx scripts/generate-github-card-data.ts && ..."

改动 2:新增一个手动执行的命令(放在 lqips 旁边):

"lqips": "npx tsx scripts/generate-lqips.ts",
"friend-json": "npx tsx scripts/generate-friend-json.ts",

2.3 执行脚本生成 public/friend.json#

Terminal window
pnpm friend-json

预期输出:

friend.json 已生成: public\friend.json (N 个友链) ← N 为你的友链数量

打开 public/friend.json 确认内容长这样:

{
"friends": [
[
"MIFENG BLOG",
"https://blog.imbee.top/",
"https://blog.imbee.top/images/logo/logo.webp"
]
]
}

2.4 新增 src/config/fcircleConfig.ts#

// 友链朋友圈 (Friend-Circle-Lite) 页面配置
export const fcircleConfig = {
// 页面标题
title: "友链朋友圈",
// 页面描述
description: "聚合朋友们的最新文章,数据来自各位友链的 RSS 订阅",
// FCL 数据站地址(fork 仓库 page 分支部署后的站点根地址,末尾必须带 /)
// 部署完成后把这里改成你自己的地址,例如 https://xxx.vercel.app/
apiUrl: "https://YOUR-FCL-DOMAIN.vercel.app/",
// 每次加载文章数量
pageSize: 24,
// 头像加载失败时的默认图片
errorImg: "/favicon/sakura2.png",
};

⚠️ 先保持占位符不动,apiUrl 在第 6 章拿到数据站地址后再回填(本文示例最终填的是 https://fc.mstzuomu.space/)。

2.5 修改 src/config/index.ts#

加一行导出(保持字母序,放在 dynamicConfig 之后):

export { dynamicConfig } from "./dynamicConfig"; // 动态页面配置
export { fcircleConfig } from "./fcircleConfig"; // 友链朋友圈页面配置

2.6 新增 src/pages/fcircle.astro(页面本体)#

完整内容:

---
import { Icon } from "astro-icon/components";
import { fcircleConfig, siteConfig } from "@/config";
import MainGridLayout from "@/layouts/MainGridLayout.astro";
// 检查页面是否启用
if (!siteConfig.pages.fcircle) {
return Astro.redirect("/404/");
}
const title = fcircleConfig.title;
const description = fcircleConfig.description;
---
<MainGridLayout title={title} description={description}>
<div
class="flex w-full rounded-(--radius-large) overflow-hidden relative min-h-32"
>
<div class="card-base z-10 px-9 py-6 relative w-full">
<!-- 页面标题和描述 -->
<div class="mb-4">
<div class="flex items-center gap-3 mb-3">
<div
class="h-8 w-8 rounded-lg bg-(--primary) flex items-center justify-center text-white dark:text-black/70"
>
<Icon name="material-symbols:public" class="text-[1.5rem]" />
</div>
<div
class="text-3xl font-bold text-neutral-900 dark:text-neutral-100"
>
{title}
</div>
</div>
{
description && (
<p class="text-base text-neutral-600 dark:text-neutral-400 leading-relaxed mb-4">
{description}
</p>
)
}
</div>
<!-- Friend-Circle-Lite 友圈文章流 -->
<link rel="stylesheet" href="/fclite/fclite.css" />
<div id="friend-circle-lite-root"></div>
<script
is:inline
define:vars={{
apiUrl: fcircleConfig.apiUrl,
pageSize: fcircleConfig.pageSize,
errorImg: fcircleConfig.errorImg,
}}
>
window.UserConfig = {
private_api_url: apiUrl,
page_turning_number: pageSize,
error_img: errorImg,
};
</script>
<script is:inline src="/fclite/fclite.js"></script>
</div>
</div>
<!--
fclite.css 依赖 [data-theme=light]/[data-theme=dark] 切换亮暗色,
而本站的 data-theme 是代码高亮主题名(one-light/one-dark-pro),
亮暗切换实际由 html.dark 控制,这里做一层变量桥接。
-->
<style is:global>
#friend-circle-lite-root {
--text-color: var(--text-color-light);
--background-color: var(--background-color-light);
--tag-bg-color: #bfbfbf;
--container-bg-color: var(--container-bg-color-light);
/* 副文本(日期、统计标签、页脚)统一到主题元信息色 */
--author-color: var(--content-meta);
--shadow-color: var(--shadow-color-light);
--border-color: var(--border-color-light);
--modal-bg-color: rgba(255, 255, 255, 0.5);
--modal-content-bg-color: rgba(239, 250, 255, 0.5);
--load-more-btn-bg-color: var(--container-bg-color);
/* 跟随站点主题色 */
--hover-color: var(--primary);
}
:root.dark #friend-circle-lite-root {
--text-color: var(--text-color-dark);
--background-color: var(--background-color-dark);
--tag-bg-color: #474747;
--container-bg-color: var(--container-bg-color-dark);
--author-color: var(--content-meta);
--shadow-color: var(--shadow-color-dark);
--border-color: var(--border-color-dark);
--modal-bg-color: rgba(0, 0, 0, 0.3);
--modal-content-bg-color: rgba(20, 20, 20, 0.5);
--load-more-btn-bg-color: var(--container-bg-color);
}
</style>
</MainGridLayout>

几个关键点解释(看懂可以更好 DIY):

  • define:vars 会把 fcircleConfig 里的值序列化进内联脚本,所以改配置文件就能改页面行为,不用动这个文件。
  • 顺序很重要:window.UserConfig 的 <script> 必须写在 fclite.js 之前——fclite.js 加载时会立即读取 UserConfig,读不到会直接报错。Firefly 的 Swup 页面切换会在每次进入页面时重新执行容器内脚本,所以从别的页面切过来也能正常渲染。
  • 底部 <style is:global> 是亮暗色桥接:FCL 原版样式用 [data-theme=light/dark] 切色,而 Firefly 的 data-theme 装的是代码高亮主题名(one-light/one-dark-pro),真正控制暗色的是 html.dark 类。不加这段,暗色模式下友圈样式会错乱。

2.7 页面开关:pages.fcircle#

文件 1 src/types/siteConfig.ts,在 pages 类型里加一行:

pages: {
booknav: boolean; // 书签导航页面开关
friends: boolean; // 友链页面开关
fcircle: boolean; // 友链朋友圈页面开关

文件 2 src/config/siteConfig.ts,在 resolvePageToggles 里加开关:

// 友链页面开关
friends: true,
// 友链朋友圈页面开关(Friend-Circle-Lite)
fcircle: true,

开关为 false 时:页面自动 404、导航菜单自动隐藏(前提是 2.8 的菜单项配了 pageKey)。还支持环境变量覆盖 PUBLIC_PAGES_FCIRCLE=false。

2.8 导航栏菜单:src/config/navBarConfig.ts#

改动 1,在「社交」子菜单里、友链之后插入:

// 友链
LinkPresets.Friends,
// 友链朋友圈
LinkPresets.Fcircle,
// 留言
LinkPresets.Guestbook,

改动 2,在 LinkPresets 表里、Friends 之后新增条目:

Friends: {
name: "友链",
url: "/friends/",
icon: "material-symbols:link-2-rounded",
pageKey: "friends",
},
Fcircle: {
name: "友圈",
url: "/fcircle/",
icon: "material-symbols:public",
pageKey: "fcircle",
},

2.9 自托管 FCL 前端文件 public/fclite/(含主题化改造)#

FCL 官方文档让你用 jsdelivr CDN 引脚本——国内不稳定,不要用。改为自托管:

  1. 打开你 fork 的仓库(第 3 章会讲怎么 fork),进入 main/ 目录
  2. 下载其中的 fclite.js 和 fclite.css 两个文件
  3. 在博客仓库新建目录 public/fclite/,把两个文件放进去

(也可以从上游仓库拿:https://github.com/willow-god/Friend-Circle-Lite 的 main/ 目录。)

拿到的原版文件是 FCL 自带画风(8px 圆角、灰底卡片、方角按钮),和 Firefly 主题不搭,而且不接入主题的卡片设置——拖透明度滑块、开关卡片边框对它完全无效。所以还要做两轮本地化改造(本文实战时改的,改处都留了「本地修改」注释方便日后比对):

改造 ①:卡片接入主题卡片系统(card-base)#

原理:Firefly 的卡片透明度、卡片边框开关、主题色相底色全部通过 .card-base 类挂钩(规则在 src/styles/main.css:.wallpaper-transparent .card-base 用 !important 吃掉一切自写背景)。FCL 原版自己写死了背景/圆角/边框,把主题系统的值全压掉了。改法 = 给卡片加上 card-base 类 + 删掉它自写的那三样属性。

fclite.js 两处:

const randomArticleContainer = document.createElement('div');
randomArticleContainer.id = 'random-article';
randomArticleContainer.classList.add('card-base');
card.className = 'card';
card.className = 'card card-base';

fclite.css 两处(只删下面标 - 的属性行,其余保留):

#random-article {
display: flex;
...
background-color: var(--container-bg-color);
border-radius: 8px;
border: 1px solid var(--border-color);
padding: 20px;
.card {
background-color: var(--container-bg-color);
border-radius: 8px;
padding: 12px;
border: 1px solid var(--border-color);
position: relative;

改完后的效果:底色 = var(--card-bg)(透明壁纸模式下自动改用滑块控制的 --card-bg-transparent)、圆角 = --radius-large(1rem,与全站卡片一致)、边框跟随「卡片边框」开关,开启时 hover 仍会变主题色高亮(原 fclite 的 hover 规则保留)。

改造 ②:内层元素统一到主题设计语言#

以下都在 fclite.css 里改。颜色一律用主题变量(用之前先在 src/styles/variables.styl 里核对存在,防止幽灵变量),对照表:

选择器对应页面元素关键改动
.stat-item订阅/活跃/文章/失败 四个统计块底色 → var(--btn-regular-bg);边框 → 1px solid var(--line-divider);圆角 → var(--radius-xl);hover 边框 → color-mix(in srgb, var(--primary) 30%, transparent)
.card-author、.random-author、.random-date名字/日期胶囊改成 category-pill 同款:底 color-mix(in srgb, var(--btn-content) 6%, transparent)、边框 color-mix(in srgb, var(--btn-content) 12%, transparent)、border-radius: var(--radius-full)、文字 var(--btn-content);hover 边框/文字 → var(--primary)
.random-button-container a「换一篇」按钮底 var(--btn-regular-bg)、边框 var(--line-divider)、圆角 var(--radius-full)、文字 var(--btn-content);hover 底 var(--btn-regular-bg-hover)
.random-link-button「阅读文章」按钮border-radius: var(--radius-full)(底色本来就是 var(--primary),不动)
#load-more-btn「再来亿点」加载按钮套「换一篇」同款 btn-regular 胶囊方案

最后回到 2.6 的 fcircle.astro:桥接块里 --author-color 两条映射改成 var(--content-meta)(代码已同步),日期文字、统计标签、页脚这些副文本就统一到主题元信息色,明暗自动适配。

⚠️ 这些改造都在你博客仓库的 public/fclite/ 里,不影响数据站。若日后从上游重新下载这两个文件,改造需要重新做一遍。

2.10 本地验证 → 推送上线#

本地验证(3 条命令):

Terminal window
pnpm check # Astro 诊断(既有的 i18n/anime 报错与本改动无关,可忽略)
pnpm lint # Biome 检查
pnpm dev # 启动后访问 http://localhost:4321/fcircle/

浏览器打开 http://localhost:4321/fcircle/,应看到:标题「友链朋友圈」、友圈数据加载中(此时 apiUrl 还是占位符,报加载失败属正常,第 6 章回填后就好)。 同时检查导航栏「社交」下多了「友圈」菜单。

提交推送:

Terminal window
git add .
git commit -m "feat: 新增友链朋友圈页面"
git push

推送后等 CI 构建完成(几分钟),然后用 curl.exe 线上验证两个关键地址:

Terminal window
# 应返回 200,且内容是你的友链名单
curl.exe -sL https://你的域名/friend.json
# 应返回 200
curl.exe -o NUL -w "%{http_code}" https://你的域名/fcircle/

friend.json 是 FCL 爬虫的输入,必须先上线,第 3 章的爬虫才能读到你的友链。顺序不能反。


3. 第二部分:Fork Friend-Circle-Lite 并配置(4 处改动)#

3.1 Fork 仓库#

  1. 打开上游仓库:https://github.com/willow-god/Friend-Circle-Lite
  2. 点右上角 Fork → Create fork(只 fork main 分支即可)
  3. 克隆到本地(换成你的用户名):
Terminal window
git clone https://github.com/你的用户名/Friend-Circle-Lite.git
cd Friend-Circle-Lite

3.2 改动 1:conf.yaml(4 处,最重要)#

这个文件是爬虫的总配置。只改值,不动结构:

配置项原值(上游)改成说明
spider_settings.json_url"https://blog.liushen.fun/friend.json""https://你的域名/friend.json"你的友链名单地址
link_check.author_url"blog.liushen.fun""你的域名"反链检测用(只填域名不带 https)
rss_subscribe.enabletruefalse邮件订阅功能,用不到就关
rss_subscribe.github_usernamewillow-god你的GitHub用户名顺手改掉
rss_subscribe.your_blog_urlhttps://blog.liushen.fun/https://你的域名/顺手改掉
rss_subscribe.website_info.title"清羽飞扬""你的博客标题"顺手改掉

对照 diff:

spider_settings:
enable: true
json_url: "https://blog.liushen.fun/friend.json"
json_url: "https://你的域名/friend.json"
article_count: 5
link_check:
...
enable_backlink_check: true
author_url: "blog.liushen.fun"
author_url: "你的域名"
rss_subscribe:
enable: true
github_username: willow-god
enable: false
github_username: 你的GitHub用户名
github_repo: Friend-Circle-Lite
your_blog_url: https://blog.liushen.fun/
your_blog_url: https://你的域名/
...
website_info:
title: "清羽飞扬"
title: "你的博客标题"

这是整个部署里最容易漏、漏了后果最严重的一步。 如果忘了改 json_url,爬虫会去爬上游作者的 200 多个友链,你的友圈页面会显示一堆陌生人(本文实战就踩过这个坑,第 9 章有排查方法)。

3.3 改动 2:新增 static/vercel.json(CORS 跨域头)#

浏览器从你的博客域名跨域请求 Vercel 数据站,对方必须返回 Access-Control-Allow-Origin: *,否则数据拉不下来。

新建文件 static/vercel.json,完整内容:

{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Access-Control-Allow-Origin",
"value": "*"
},
{
"key": "Access-Control-Allow-Methods",
"value": "GET, POST, OPTIONS, PUT, DELETE"
},
{
"key": "Access-Control-Allow-Headers",
"value": "*"
}
]
}
]
}

为什么放 static/ 而不是仓库根目录?因为 Actions 工作流会把 static/ 里的指定文件拷贝进 page 分支,而 Vercel 部署 page 分支时只认分支根目录的 vercel.json。下一步就是把这个文件加进拷贝清单。

3.4 改动 3:.github/workflows/friend_circle_lite.yml#

找到 Build static publish directory 步骤里的 cp 命令,在清单里加上 ./static/vercel.json:

- name: Build static publish directory
run: |
mkdir pages
cp -r main ./static/edgeone.json ./static/_headers ./static/index.html ./static/readme.md ./static/favicon.ico ./static/bg-light.webp ./static/bg-dark.webp all.json link.json errors.json pages/
cp -r main ./static/edgeone.json ./static/_headers ./static/vercel.json ./static/index.html ./static/readme.md ./static/favicon.ico ./static/bg-light.webp ./static/bg-dark.webp all.json link.json errors.json pages/

3.5 改动 4:.gitignore#

仓库的 .gitignore 忽略了所有 *.json(防止数据文件进主分支),需要给 vercel.json 开例外,否则它永远推不上去:

# 忽略数据文件
*.json
!edgeone.json
!vercel.json

3.6 提交并推送#

Terminal window
git add conf.yaml .gitignore .github/workflows/friend_circle_lite.yml static/vercel.json
git commit -m "fix: 友链数据源指向本站并为 page 分支添加 Vercel CORS 配置"
git push

⚠️ 核对清单:git status 确认这 4 个文件都进了提交。实战中曾出现”以为推了实际没推”的情况,导致爬虫用了上游的友链列表。推完可以去 GitHub 网页上点开 conf.yaml 确认 json_url 已经是你的域名。


4. 第三部分:启用 GitHub Actions,生成 page 分支#

FCL 的数据完全由 GitHub Actions 定时生成,部署在免费额度内(公开仓库无限,私有仓库每月 2000 分钟,这个爬虫每次不到 2 分钟,绰绰有余)。

4.1 启用工作流(fork 有两道开关,都要点!)#

开关 ①:打开 https://github.com/你的用户名/Friend-Circle-Lite/actions 顶部会有条黄色提示 “Workflows aren’t being run on this forked repository…” → 点 “I understand my workflows, go ahead and enable them”。

开关 ②(很多人卡在这):左侧工作流列表里,Friend Circle Lite 可能仍显示 「已禁用」(fork 特有的 disabled_fork 状态)—— → 点击左侧的 Friend Circle Lite → 工作流页面点绿色 “Enable workflow” 按钮。

只启用开关 ① 不启用开关 ②,手动触发会报 422 Cannot trigger a 'workflow_dispatch' on a disabled workflow。

4.2 手动运行一次#

  1. 左侧点 Friend Circle Lite
  2. 右上角 Run workflow → 下拉选 main → 点绿色 Run workflow
  3. 等 1~2 分钟刷新,看到绿色 ✅ success 即可(首次运行要下载依赖,慢一点正常)

这次运行会:

  • 读取你博客上线的 friend.json(你的友链名单)
  • 检测每个友链可达性 + 抓取 RSS 文章
  • 生成 all.json / link.json / errors.json
  • 强制推送 page 分支(首次创建)

4.3 验证 page 分支#

打开 https://github.com/你的用户名/Friend-Circle-Lite/tree/page,确认存在:

  • all.json(点开能看到 "friends_num": 你的友链数)
  • link.json
  • vercel.json(重点:没有它 CORS 会挂)
  • main/、index.html 等静态文件

5. 第四部分:Vercel 部署数据站#

5.1 导入仓库#

  1. 登录 vercel.com → Add New… → Project
  2. 在仓库列表里找到 Friend-Circle-Lite 点 Import(首次会让你安装/授权 Vercel 的 GitHub App,按提示授权)
  3. 构建配置全部保持默认即可(main 分支没有构建步骤,仓库根目录的 vercel.json 里 deploymentEnabled.main: false 会让它跳过 main 分支的部署——这是上游作者设计好的)
  4. 等导入完成

5.2 把生产分支改成 page(关键步骤)#

进入项目 → Settings → Environments → Production,找到 Branch Tracking:

  • 把分支从 main 改成 page → 点 Save

两个坑:

  1. 报错 Branch "page" not found in the connected Git repository —— 说明第 4 章还没跑成功、page 分支不存在。回去先完成第 4 章再来。
  2. 新版 Vercel 界面里没有单独的 “Production Branch” 选项(旧教程会误导你去 Git 页找)——它就在上面说的 Environments → Production → Branch Tracking 里。找不到就用 Settings 页左侧顶部的 Find 搜索框搜 production。

5.3 首次生产部署#

保存成功后 Vercel 通常会弹出 Redeploy 对话框:

  • 环境选 Production
  • 源部署选带 page 分支标记的那条(列表里最新的)
  • 点 Redeploy

如果没弹窗,去 Deployments 页找到 page 分支的那条部署 → 右侧 … → Promote to Production。

完成后,项目的生产地址(形如 friend-circle-lite-xxx.vercel.app)就由 page 分支驱动了——以后 Actions 每次推送,Vercel 自动部署,无需任何手动操作。

5.4 绑定自定义子域名(国内必做)#

为什么必须:*.vercel.app 域名在国内被 DNS 污染(解析出假 IP),你的访客会全部加载失败。实测必须绑自有域名。

第 1 步 — Vercel 侧添加域名:

项目 → Settings → Domains → 输入你想用的子域名(例:fc.你的域名)→ Add。 添加后 Vercel 会提示需要一条 CNAME 记录(目标是 cname.vercel-dns.com)。

第 2 步 — Cloudflare 侧加 DNS 记录:

Cloudflare 控制台 → 你的域名 → DNS → Records → Add record:

字段填写
TypeCNAME
Namefc(对应 fc.你的域名 的前缀)
Targetcname.vercel-dns.com
ProxyDNS only(一定选灰云,不要开橙色云代理)
TTLAuto

第 3 步 — 回 Vercel 等证书签发:

DNS 生效通常 1~5 分钟。如果域名状态显示证书错误,点 Refresh / 重新保存一次域名即可触发重新签发。

验证:

Terminal window
# 应返回 200,并且能看到 Access-Control-Allow-Origin: *
curl.exe -sI https://fc.你的域名/all.json

响应头里必须有这一行,缺了就回头检查 page 分支上有没有 vercel.json(第 3.3/3.4 步)。


6. 第五部分:回填数据站地址,全线贯通#

打开 src/config/fcircleConfig.ts,把占位符换成你的真实数据站地址(末尾的 / 不能少):

// FCL 数据站地址(fork 仓库 page 分支部署后的站点根地址,末尾必须带 /)
apiUrl: "https://YOUR-FCL-DOMAIN.vercel.app/",
apiUrl: "https://fc.你的域名/",

提交推送:

Terminal window
git add src/config/fcircleConfig.ts
git commit -m "feat: 回填友圈数据站地址"
git push

等博客 CI 部署完成(几分钟),最终验证:

Terminal window
# 1. 页面 HTML 里已包含新地址
curl.exe -sL https://你的域名/fcircle/ | findstr "fc.你的域名"
# 2. 数据接口 200 + CORS + 你的友链数
curl.exe -sI https://fc.你的域名/all.json

浏览器打开 https://你的域名/fcircle/ —— 看到自己朋友们的最新文章,部署完成 🎉

页面如果还显示旧数据/加载失败:FCL 前端有 10 分钟 localStorage 缓存,等 10 分钟再刷新,或开无痕窗口立即查看。


7. 成品验收清单#

逐项打勾,全过即部署成功:

#检查项验证方法预期
1友链名单已上线curl.exe -sL https://你的域名/friend.json200,friends 数量 = 你的友链数
2页面已上线浏览器打开 /fcircle/200,标题「友链朋友圈」
3导航菜单导航栏「社交」下拉有「友链」和「友圈」两项
4Actions 正常fork 的 Actions 页最近一次运行是绿色 success
5page 分支github.com/你/Friend-Circle-Lite/tree/page有 all.json / link.json / vercel.json
6数据站可达curl.exe -sI https://fc.你的域名/all.json200 + Access-Control-Allow-Origin: *
7数据是你的友链浏览器打开 https://fc.你的域名/all.jsonfriends_num = 你的友链数,作者都是你朋友
8文章渲染无痕窗口打开 /fcircle/文章卡片正常显示,点「换一篇」「阅读文章」可用
9自动更新等一个 cron 周期(≤4 小时)后看 last_updated_time时间刷新
10亮暗色切换博客暗色模式友圈样式跟随切换、无错乱
11卡片跟随主题设置拖「卡片透明度」滑块、开关「卡片边框」统计面板与文章卡片底色/边框同步变化(未做 2.9 改造则此项不过)

8. 自动化之后:日常运行说明#

部署完成后你什么都不用做,全自动链路:

每 4 小时 (cron: 22 */4 * * * UTC,即北京时间 00:22 / 04:22 / 08:22 / 12:22 / 16:22 / 20:22)
└─ GitHub Actions 爬虫运行
├─ 检测友链可达性(结果缓存 24 小时,不会频繁骚扰友链站点)
├─ 抓取各站 RSS 最新文章
├─ 生成 all.json / link.json
└─ 推送 page 分支
└─ Vercel 自动生产部署 → fc.你的域名 更新
└─ 博客 /fcircle/ 下次访问即是新数据

常见日常操作:

  • 改了友链配置:改 friendsConfig.ts → 推送博客(friend.json 自动更新)→ 下一个爬虫周期生效。想立即生效就去 fork 的 Actions 手动 Run workflow 一次。
  • 想手动立刻刷新数据:fork → Actions → Friend Circle Lite → Run workflow,约 90 秒完成并自动上线。
  • 看哪些友链挂了:打开 https://fc.你的域名/(FCL 自带的展示首页有可达性列表),或看博客友圈统计里的「失败」数。

数据字段含义(友圈顶部统计条):

字段含义
订阅友链总数
活跃可达且能抓到 RSS 的站点数
文章聚合的文章总数
失败不可达 / 没有 RSS / 抓取失败的站点数(有几台挂了属正常现象,不是你的部署问题)

9. 踩坑排查表(本文实战遇到的全部问题)#

现象原因解决
Actions 页显示「无工作流程运行」,列表里工作流带「已禁用」fork 仓库有两道开关:仓库级启用 + 单个工作流启用第 4.1 章:先点 “I understand my workflows…”,再进工作流页点 “Enable workflow”
手动触发报 422 Cannot trigger a 'workflow_dispatch' on a disabled workflow同上,第二道开关没开同上
Vercel 报 Branch "page" not foundpage 分支还不存在先成功运行一次 Actions(第 4 章),再回来保存
找不到 “Production Branch” 设置Vercel 新版 UI 已移动位置Settings → Environments → Production → Branch Tracking;或左侧 Find 搜 production
友圈显示的全是陌生人(200+ 订阅,作者都不认识)conf.yaml 的 json_url 还指向上游作者的友链列表(改动没推送成功)改 conf.yaml → git add 确认 → 推送 → 手动 Run workflow → 核对 page 分支 all.json 的 friends_num
友圈页面一直加载中/加载失败apiUrl 占位符没回填、末尾漏 /、或数据站 CORS 头缺失第 6 章回填;curl.exe -sI 检查 Access-Control-Allow-Origin: *;确认 page 分支有 vercel.json
数据站地址国内打不开*.vercel.app 被 DNS 污染第 5.4 章绑定自定义子域名(CNAME 到 cname.vercel-dns.com,灰云)
页面数据是旧的fclite.js 有 10 分钟 localStorage 缓存 + 浏览器缓存等 10 分钟或无痕窗口刷新
友圈数据突然变回旧数据(或又出现陌生人文章)Vercel 的 Redeploy 弹窗里选中了历史旧部署并发布,生产被回滚Deployments 列表核对最新一条 page 部署的时间 → 对最新的那条执行 … → Promote to Production;别选日期是几天前的部署
证书签发失败 / 域名一直 PendingDNS 还没生效等 1~5 分钟,在 Vercel Domains 页 Refresh 重试;确认 Cloudflare 里是灰云
PowerShell 里 curl -sI 报”参数无效”PS5.1 把 curl 别名成 Invoke-WebRequest一律写 curl.exe
pnpm check / type-check 一堆报错项目既有问题(i18n 缺键、anime/vndb 页)与本教程无关,只看你新增文件有没有报错
pnpm lint 把一堆无关文件改了格式biome check --write 会顺手格式化git checkout -- <无关文件> 还原,只保留自己的改动
本机构建报 unable to verify the first certificate(OG 图片生成)本机网络环境的 TLS 证书链问题set NODE_OPTIONS=--use-system-ca 后重跑,或忽略(CI 上不会出现)
本地跑 FCL 爬虫报 ZoneInfoNotFoundError: Asia/ShanghaiWindows 的 Python 缺 tzdata 包pip install tzdata(见附录 B)

10. 安全收尾(推荐)#

如果你在部署过程中用过 API Token(比如为了用 CLI 部署临时生成的 Vercel Token):

  1. vercel.com → Settings → Tokens → 删除用完的 token
  2. 清理本机临时凭据文件(如果有)
  3. 检查 fork 仓库:Settings → Actions → General → Workflow permissions 确认是 Read repository contents and permissions(本教程的工作流文件里已显式声明 contents: write,够用,无需给默认权限开写)

附录 A:文件改动总清单#

博客仓库(FireflyPriWeb):

文件操作
scripts/generate-friend-json.ts新增
package.json修改(build 链 + friend-json 命令)
public/friend.json脚本生成(勿手改)
src/config/fcircleConfig.ts新增
src/config/index.ts修改(+1 行导出)
src/pages/fcircle.astro新增
src/types/siteConfig.ts修改(pages.fcircle 类型)
src/config/siteConfig.ts修改(pages.fcircle 开关)
src/config/navBarConfig.ts修改(Fcircle 菜单项 ×2 处)
public/fclite/fclite.js、fclite.css新增(从 fork 的 main/ 目录复制,并按 2.9 完成两轮主题化改造)

FCL fork 仓库:

文件操作
conf.yaml修改(json_url / author_url / rss_subscribe 共 6 处值)
static/vercel.json新增
.github/workflows/friend_circle_lite.yml修改(cp 清单 +1 文件)
.gitignore修改(!vercel.json)

平台侧配置(非代码):

位置操作
GitHub fork → Actions启用仓库 workflows + 启用 Friend Circle Lite 工作流
Vercel 项目 → EnvironmentsProduction 分支 = page
Vercel 项目 → Domains添加 fc.你的域名
Cloudflare DNSCNAME fc → cname.vercel-dns.com(灰云)
博客 fcircleConfig.apiUrl回填数据站地址

附录 B(可选方案):不用 GitHub Actions,本地 Python 爬虫手动部署#

适用于:想本地先跑通看看效果,或不想用 Actions 的场景。

Terminal window
cd Friend-Circle-Lite
python -m venv .venv
.venv\Scripts\python.exe -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests feedparser PyYAML jinja2 python-dateutil tzdata
.venv\Scripts\python.exe run.py # 生成 all.json / link.json / errors.json

注意两点:

  • 国内直连 PyPI 会超时,务必加清华镜像 -i https://pypi.tuna.tsinghua.edu.cn/simple;Windows 必须装 tzdata。
  • 生成后把 main/、static/ 下的指定文件、vercel.json 和三个 json 拷到一个目录,用 Vercel CLI 部署:
Terminal window
npm install vercel --registry=https://registry.npmmirror.com # npmjs 被墙时用 npmmirror
vercel deploy --prod --token=你的token

但此方式数据不会自动更新(每次都要手动跑),正式使用推荐本文正文的 GitHub Actions 方案。


附录 C:把本文发布到你的博客#

想把这篇教程作为博客文章发布:

Terminal window
pnpm new-post

把本文内容粘进生成的 md 文件,补上 frontmatter(标题、日期、分类、标签),放 src/content/posts/ 下推送即可。若你的博客启用了友圈失败站点的评论系统接入,按 Firefly 惯例在 frontmatter 加 comment: true。


教程基于实战部署整理:Firefly 6.16.7 + Friend-Circle-Lite(v2.x)+ Vercel Hobby + Cloudflare DNS。文中示例域名 mstzuomu.space / fc.mstzuomu.space 请替换为你自己的。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
Firefly 博客接入友链朋友圈:从零开始的完整部署教程
https://mstzuomu.space/posts/azuma.zuomu-blog-12/
作者
陌殊途左沐
发布于
2026-09-26
许可协议
CC BY-NC-SA 4.0
相关文章智能推荐
1
Firefly 博客实战:给文章页加阅读进度条与圆环百分比
技术分享从设计思路到逐文件代码,手把手为 Firefly/Astro 博客实现纯客户端阅读进度功能:顶部细条、右下角与悬浮按钮同款的圆环百分比,零网络请求,兼容 Swup 切页
2
博客性能优化全记录:Lighthouse 报告拆解到帧率根因排查(A–F 六项实战)
技术分享从两份 Lighthouse 对比报告出发,完整记录六项性能优化的排查方法、根因定位与修复代码:字体子集化、封面图尺寸 API、CSS 内联、强制重排归零、以及"只有 Chrome 掉帧"的浏览器设置级根因,附全部可复现命令与工具脚本
3
Firefly 博客实战:从零搭建任意设备可用的发布台(Vercel + GitHub API)
技术分享静态博客只能守在电脑前发文章?本文完整复盘如何用 Vercel 无框架函数 + GitHub API 搭一套带登录的发布后台——发文、改稿、删除、预览全部在浏览器里完成,附我们真实踩过的五个部署坑与安全边界设计,照着做可以从零复刻。
4
导航栏 UI 改造全记录:卡片边框、悬浮胶囊、三段收拢与 PC 收拢态快捷面板(附完整复现指南)
技术分享一次连续迭代的完整复盘——从卡片边框体系、悬浮胶囊导航,到三段结构拆分、下滑收拢动画,再到 PC 收拢态汉堡的控件快捷面板与"行点击原位弹卡"的两处根因修复,追加 PC 搜索控件图标化与收拢动画卡顿的逐帧诊断修复。每个批次改了哪些文件、为什么这么改、踩了哪些坑(CSS 层序、正圆公式、包含块、Vite 缓存、Playwright headless 动画冻结),附 git 重放与手工重做两条复现路径及验收清单
5
Win11 资源管理器大小列只显示 KB?开启 KB / MB / GB 自适应显示完整教程
技术分享Win11 详细信息视图的大小列长期以来一律用 KB 显示,4 GB 的文件写成 4,194,304 KB 根本没法看。微软其实已经原生支持自适应单位了,本文给出先更新系统、再用 ViveTool 强制开启(功能 ID 61014711)的完整教程,含回滚方法与常见问题。
随机文章随机推荐

评论区

Profile Image of the Author
陌殊途左沐
热爱是拯救无趣人生的唯一途径
公告
欢迎来到我的博客!这里是左沐的个人空间,分享我的学习、生活和兴趣爱好。希望你能在这里找到有趣的内容,请不要对我的喜好做出评价哦!请勿使用公网访问本站。
分类
访客信息
加载中...
标签
最新动态
站点统计
文章
27
分类
2
标签
47
总字数
48,093
运行时长
0 天
最后活动
0 天前
总浏览量
-
访客数
-
1
Firefly 博客接入「友链朋友圈」完整部署教程
0. 先搞懂原理:三个部分怎么协作
1. 准备工作
2. 第一部分:博客侧代码改造
2.1 新增 scripts/generate-friend-json.ts
2.2 修改 package.json
2.3 执行脚本生成 public/friend.json
2.4 新增 src/config/fcircleConfig.ts
2.5 修改 src/config/index.ts
2.6 新增 src/pages/fcircle.astro(页面本体)
2.7 页面开关:pages.fcircle
2.8 导航栏菜单:src/config/navBarConfig.ts
2.9 自托管 FCL 前端文件 public/fclite/(含主题化改造)
2.10 本地验证 → 推送上线
3. 第二部分:Fork Friend-Circle-Lite 并配置(4 处改动)
3.1 Fork 仓库
3.2 改动 1:conf.yaml(4 处,最重要)
3.3 改动 2:新增 static/vercel.json(CORS 跨域头)
3.4 改动 3:.github/workflows/friend_circle_lite.yml
3.5 改动 4:.gitignore
3.6 提交并推送
4. 第三部分:启用 GitHub Actions,生成 page 分支
4.1 启用工作流(fork 有两道开关,都要点!)
4.2 手动运行一次
4.3 验证 page 分支
5. 第四部分:Vercel 部署数据站
5.1 导入仓库
5.2 把生产分支改成 page(关键步骤)
5.3 首次生产部署
5.4 绑定自定义子域名(国内必做)
6. 第五部分:回填数据站地址,全线贯通
7. 成品验收清单
8. 自动化之后:日常运行说明
9. 踩坑排查表(本文实战遇到的全部问题)
10. 安全收尾(推荐)
附录 A:文件改动总清单
附录 B(可选方案):不用 GitHub Actions,本地 Python 爬虫手动部署
附录 C:把本文发布到你的博客
文章目录
1
Firefly 博客接入「友链朋友圈」完整部署教程
0. 先搞懂原理:三个部分怎么协作
1. 准备工作
2. 第一部分:博客侧代码改造
2.1 新增 scripts/generate-friend-json.ts
2.2 修改 package.json
2.3 执行脚本生成 public/friend.json
2.4 新增 src/config/fcircleConfig.ts
2.5 修改 src/config/index.ts
2.6 新增 src/pages/fcircle.astro(页面本体)
2.7 页面开关:pages.fcircle
2.8 导航栏菜单:src/config/navBarConfig.ts
2.9 自托管 FCL 前端文件 public/fclite/(含主题化改造)
2.10 本地验证 → 推送上线
3. 第二部分:Fork Friend-Circle-Lite 并配置(4 处改动)
3.1 Fork 仓库
3.2 改动 1:conf.yaml(4 处,最重要)
3.3 改动 2:新增 static/vercel.json(CORS 跨域头)
3.4 改动 3:.github/workflows/friend_circle_lite.yml
3.5 改动 4:.gitignore
3.6 提交并推送
4. 第三部分:启用 GitHub Actions,生成 page 分支
4.1 启用工作流(fork 有两道开关,都要点!)
4.2 手动运行一次
4.3 验证 page 分支
5. 第四部分:Vercel 部署数据站
5.1 导入仓库
5.2 把生产分支改成 page(关键步骤)
5.3 首次生产部署
5.4 绑定自定义子域名(国内必做)
6. 第五部分:回填数据站地址,全线贯通
7. 成品验收清单
8. 自动化之后:日常运行说明
9. 踩坑排查表(本文实战遇到的全部问题)
10. 安全收尾(推荐)
附录 A:文件改动总清单
附录 B(可选方案):不用 GitHub Actions,本地 Python 爬虫手动部署
附录 C:把本文发布到你的博客