FIELD NOTE
把博客框架拆成独立仓库:FlowyBlog Framework 诞生记
记录把博客仓库一分为二的过程:哪些东西留在原站、哪些交给框架仓库、占位符化怎么改、双仓库之后上游同步怎么做,以及拆分时遇到的实际冲突。
正文宽度
拆分之前,这个博客是一个单仓库:文章、外观、评论系统、液态玻璃渲染器、后台管理,全部长在一起。它可以用,但有两个问题越来越明显。
一是职责混在一起。改一处间距、调一个封面配色,提交记录里和文章发布混在同一份历史里,时间久了自己都分不清哪次提交动了外观、哪次只动了文字。二是没法分享。有朋友问这个站能不能拿来自己搭一个,答案是“可以,但你得先把我的文章删干净、把我的站名换掉、把我的评论区配置一个个找出来改”——宛如“交接现场”。
所以 10 月 11 日,我把它拆成了两个仓库。这篇文章记录拆的思路、具体做了什么改动,以及拆完之后两个仓库怎么维持关系。
拆分方案:一份基线,两个方向
拆分没有用 fork,也没有用 git filter 去裁剪历史,而是选了一个更朴素的办法:以当时的博客仓库为基线,复制一份出来作为框架仓库的起点,然后两边各自往前走。
基线定在原仓库的提交 fc9eb3f(“优化行号显示效果”)。这个点之后,原仓库只继续收文章内容和站点配置类的改动,UI 和框架能力的改动都落到新仓库。框架仓库的提交历史从零开始,干净,代价是两边共享了一段时间的相同代码,之后要靠人工对账。
为什么不用 fork?fork 会带着全部提交历史,看起来省事,但框架仓库需要的是一份“通用的、占位符化的”代码,和博客仓库的实际配置从拆分那一刻起就分道扬镳了。带着历史只会让后来的提交看起来像是“博客仓库的又一天”,对想拿它建站的人没有任何帮助,反而让仓库显得杂乱。
拆分后的分工用一句话就能说清:
| 仓库 | 职责 | 地址 |
|---|---|---|
| 本博客 | 文章内容、站点配置、个性化外观 | 也就是你现在看的这个站 |
| 框架 | 页面、组件、评论、实验室、部署向导 | flowyblog-framework |
本站底栏的签名也随之一换,原来是“风不止,但行有恒。”,现在是“Powered by FlowyBlog Framework”。
占位符化:把“我的”从框架里拿掉
复制出框架仓库后,做的第一件事不是加功能,而是把所有属于“风不止”的痕迹拿掉。这一步比想象中琐碎,因为个人痕迹散落在很多地方:
site.ts里的站名、作者、简介、域名、GitHub 链接,全部换成占位值,改成“通常只需要改这一个文件”的结构。- 顶栏头像原来是一张图片,框架版改成纯 CSS 渲染——圆形底色加上站名首字,自动从
siteConfig.name里取第一个字符。新用户不改任何东西也有一个体面的 logo,想换图再填一个路径。 - 文章清到只剩一篇
1-hello-world.mdx示例,标签、归档、搜索索引都基于它重新生成,更多示例文章在随后补上。 - 底栏和“关于”页的授权文案改成框架视角的写法,
LICENSE.content默认留空,框架不替建站的人决定文章协议。
功能层面则一项都没砍:评论和后台、液态玻璃、书本模式、赛博朋克、阅读宽度档位、全站搜索,全部保留。框架仓库的定位是“别人拿到就能用的完整博客”,少一块功能就少一类用户。
这里有个细节值得记一笔。原来的顶栏 logo 走 next/image,静态导出构建会关闭图片优化器(images.unoptimized),图片直接输出原图路径,这是安全的;真正会静默 404 的是依赖 /_next/image 优化接口的写法——静态产物里不存在那个路由。占位符化之后每次改图片相关代码,都得跑一次导出构建验证,不能只看 pnpm dev 的表现。
给框架补上安装向导
博客是自己给自己写的,所以从来不需要“安装”这一步。框架不一样,别人 clone 下来面对的是一堆要改的配置:站点信息、Cloudflare 授权、D1 建库、密钥生成、Pages 发布。让每个建站的人手工走一遍这些步骤,出错率会很高——尤其 D1 绑定和密钥这种做错一次就得很隐蔽地排查的东西。
所以框架仓库补了一个安装向导,这是拆分后新增的、原博客没有的部分:
pnpm run setup # 命令行向导
pnpm run setup:ui # 本地 WebUI 向导向导按顺序做完:站点信息配置(自动改写 site.ts)→ 环境检测 → Cloudflare 登录 → 创建并初始化 D1 → 生成密钥写入 .dev.vars → 静态导出并发布。整个流程做成了幂等的,中断之后重跑会跳过已经完成的步骤。WebUI 版本复用同一套步骤实现,只是加了一层图形界面订阅 JSON 事件流。
有个小坑写在 README 里了:命令必须带 run,裸敲 pnpm setup 是 pnpm 的内建命令,会被 pnpm 自己拦截,报错信息完全不会让你联想到是命令名撞了。
双仓库之后,怎么同步
拆分真正的成本在拆完之后。原博客这边继续开发,遇到 UI 类改动时,它同时是框架的候选改动,需要决定要不要搬过去。
我给自己定的流程是:以基线 fc9eb3f 为参照,原仓库的每个 UI 提交都和基线做 diff,看这段改动在框架仓库里是否同样成立,成立就手工搬到框架仓库。没有用 git cherry-pick,原因是具体的:拆分时 site.ts、site-logo.tsx、site-chrome.tsx、post-card.tsx 和“关于”页这几处都被重写过——博客版保留个人配置,框架版是占位符版本。cherry-pick 会把这些文件的上下文对不上号,冲突解起来反而比照着 diff 手写慢,还容易把个人配置误搬进框架。
实际跑过几次之后,这条流程基本成立,但有两条经验值得留下来:
- 搬运要趁早。原仓库的 UI 提交攒得越多,和框架仓库的偏差越大,后来单个提交的 diff 参照的上下文就越可能已经变样。小步快搬,每次搬运都很小;攒一个月再搬,就是一次小型移植工程。
- 不是所有 UI 提交都该搬。博客这边出于个人口味做的微调(比如某个间距只有我的文章布局需要),留在原仓库就好。判断标准是“框架的用户会不会也想要”。
反过来,框架仓库的更新也要回流到博客。已经做过一轮了:框架后来加了 basePath 支持、图片 logo 和 LaTeX 公式渲染,博客这边对照着把上游改动合并回来,合并的难点和上面一样,集中在那几个被重写过的文件。
授权怎么处理
框架是 AGPL-3.0,这个决定其实拆分之前就做出了——因为液态玻璃第三版引入的 liquid-glass-webgl 是 AGPL,通过网络提供服务时提供完整源码的义务覆盖整个服务,当时整站源码就已经改成 AGPL 发布了。框架仓库沿用同一个协议,顺理成章。
对想拿框架建站的人,这件事的影响写在 README 里:推荐 fork 仓库而不是下载压缩包,因为 fork 之后你提交的两个配置文件就让仓库变成你自己的站,同时天然满足 AGPL“向访客提供源码”的义务,还能随时拉取框架更新。文章内容的授权框架不插手,site.ts 里留了位置,想允许转载就自己填 CC 系列条款,默认留空等于保留所有权利。
拆完之后
现在两个仓库各干各的:写文章只动这个仓库,改外观和框架能力去框架仓库,本站通过对照基线 diff 把上游更新接回来。首页和文章页看不出任何变化——拆分是一次对读者完全不可见的重构,但它把“我的博客”和“一个可以被别人用的博客框架”分开了。 后续计划做一个同步脚本,把现在基于基线 diff 手动搬运的流程自动化——框架仓库有新提交时,原博客这边跑一行命令就能对比差异、提示冲突点甚至自动合并非个性化改动,把”手动对账“的环节压到几乎为零。
如果你也想搭一个这样的站:fork FlowyBlog Framework,clone 下来跑 pnpm run setup:ui,跟着向导走完就能在 Cloudflare Pages 上线,全程免费额度够用。本站的实验功能(液态玻璃、书本模式、赛博朋克)框架里都有,在 /lab 页面打开。感觉好用就点个 Star ,也欢迎有能力的伙伴自己修改代码,有好想法提个 PR 。
DISCUSSION
留言
正在加载留言…