1800 字
9 分钟
– 次浏览
– 位访客
给博客配一个桌面端后台:从 CLI 原型到轻阅集成
AI 摘要
正在生成摘要…

起因:一篇别人的 CLI 文章#

前两天刷到 Zero 的《给博客写个本地管理 CLI》(vtdd.vip),他给自部署的 Firefly 博客写了约 400 行纯标准库 Python:本地建文、写动态、管友链,然后 SMB 推服务器、SSH 触发 Docker 重建。感觉想法很有意思,值得抄🐶

对照本站现状,当时判断真正值得抄的就三样:

  1. 内容操作命令化:建文、加友链、发布,都收敛成一条命令或一个按钮;
  2. 友链数组定位技术:用括号深度配对在源码里精确定位数组边界,只动数组体、绝不碰其他代码;
  3. 工程习惯:所有写操作支持 --dry-run 演练,发布前显式确认。

第三点一直留到了现在,第二点做了又亲手删掉——后面会讲为什么。

第一阶段:CLI 原型#

先做了个零依赖的 Node 原型 scripts/blog.mjs(约 250 行),验证算法可行性:

  • post "标题":生成规范 frontmatter(published 自动填当天、CRLF 行尾),slug 强校验 ^[a-z0-9]+(-[a-z0-9]+)*$——中文标题必须显式给英文 slug,否则拒绝,从源头杜绝百分号编码的 URL;
  • friend-add "名字" -u URL:括号深度配对定位 friends 数组,只在数组尾部插入对象块,重名/重 URL 直接拒绝;
  • publish:列出 git 变更 → 交互输入 yes 确认 → add + commit + push。

核心算法其实是那个「括号深度定位」:从数组声明行开始逐字符扫描,遇 [ 深度 +1、遇 ] 深度 -1,深度归零的位置就是数组结尾,插入点定在最后一个 } 之后。这样做的好处是正则只负责找起点,结构靠扫描确定,不会被代码格式变化搞崩。

原型测试通过后问题来了:CLI 再顺手,也得切终端、敲命令。我日常写文章用的编辑器是自托管的 Wails 应用「轻阅」(Go + 原生 JS 的桌面 Markdown 编辑器)。

第二阶段:集成进轻阅#

Wails v2 的绑定机制对这种集成非常友好:Go 端 App 结构体上的公开方法,构建时自动生成前端可调用的绑定。所以整件事的架构就是:

前端面板(JS) ──桥接──> Go 方法(blog.go) ──> 直接读写博客仓库

Go 端现在落了 10 个方法:

方法职责
GetBlogSettings / SetBlogSettings仓库路径、git 路径的持久化配置
SelectBlogRepo弹系统文件夹选择框,并自动定位到仓库根
GetBlogRepoInfo当前连接状态:仓库名、分支、文章数
ListBlogPosts解析每篇的 frontmatter,按日期排序
CreateBlogPost建文(slug 可留空自动生成、重名去重、原子写入)
UpdateBlogPostMeta改标题 / 描述 / 标签 / 分类 / 草稿 / 隐藏
DeleteBlogPost删文
PreviewBlogPublishgit status 预览变更 + 默认提交说明
PublishBlogadd → commit → push,带超时保护

几个设计决定值得展开:

配置校验前置。保存仓库路径时立刻检查目标目录含 .git 和 src/content/posts,把”路径填错”拦在配置阶段,而不是等到列表拉空了再排查。

发布必须显式确认。push 就是”下令上线”,静默 push 等于替用户做决定。这也是从 CLI 的 yes 确认机制原样继承来的。

文章列表点击即编辑。列表返回每篇的绝对路径,点击直接在编辑器里打开该 md,写完回面板点发布——整个闭环不离开轻阅。

第三阶段:把 frontmatter 当数据结构读#

返工过程中挖出来一个更隐蔽的坑:文章列表里一堆标题带着引号、分类和标签是空的。

排查下来,问题不在文章,在读取:原来的 frontmatter 解析是一堆硬编码正则,只认「Fuwari 新建脚本写出来的那一种格式」。回头扫了一遍自己仓库,46 篇文章里:

项被读错的篇数
标题带引号(连 '…' 的引号一起读进来)28
分类读空45
标签读空(tags: [a, b] 行内数组不被识别)35

也就是说,文件本身一个字没错,是读法只认一种写法。

于是把解析层整个重写成 YAML 感知:单引号 / 双引号 / 裸值统一剥离(含 ''、\" 这类转义),块序列 - item 和行内 [a, b] 都支持,日期认 published 也认 date,开头有 BOM 也不影响。写入侧反过来保证合法——值里含 : 、 # 这类会被 YAML 误读的内容时自动加引号,同时保留原行的引号风格,不产生无谓的 diff。

顺手把编辑器预览也修了。之前预览完全没有 frontmatter 处理,--- 之间的 YAML 被当成普通段落,软换行一折叠,整块挤成一行带蓝色链接的文字。现在前言不进正文,而是在预览顶部渲染成一张元信息卡片:封面缩略图、标题、日期、分类、标签胶囊,草稿 / 隐藏 / 加密自动出徽标。

这里有个必须守住的约束:预览的「跟随光标滚动」和「点预览跳源码」靠行号映射,删行会让整篇错位。所以前言行是原地清空而不是删除——正文块的行号仍然指向源文档里的真实行。另外导出 PDF 和长图时会把这张卡片剔掉,前言属于元信息,不该跟着正文一起导出去。

部署链路:编辑器和 CF Pages 之间没有魔法#

集成完成后,整条链路是这样的:

轻阅写文章(直接写进博客仓库源码)
↓ 点「发布」
git add → commit → push 到 GitHub main
↓ push 触发
CF Pages 自动拉源码 → 云端 pnpm build
↓ 约 80 秒
blog.142588.xyz 生效

关键理解:编辑器和 Cloudflare 之间没有任何直接通信。CF Pages 之前绑定仓库时就配好了”监视 main 分支”,push 就是扳机,云端构建全自动。本地从头到尾不需要构建——本地 dist 只是预览用的临时产物。

于是写作流收敛成:轻阅里写 → 点发布 → 确认 → 80 秒后上线。以前”写完 md、切终端、敲 git 命令、等构建”的流程,现在只剩一个按钮。

尾巴#

回头看,真正花时间、真正有意义的不是算法(AI 时代的 VibeCoding 已经能很好地完成代码撰写),而是你能利用手上的 AI 搭建属于自己的工具链,把好想法付诸现实。AI 工具以及工具链的意义就在于此:把重复劳动压到零,把注意力还给内容本身。

如果非要再提炼一条:给自己做工具,最该舍得的是删。第一版加了友链、加了检查变更、加了必填 slug,看着功能齐全,用起来处处是坎;返工那天做的事几乎全是减法。工具是给自己用的,用得顺比看着全重要得多。

PS---这篇文章从轻阅面板里点开、检查、发布——它自己就是第一个用这套流程上线的作品。(2026-09-18 补记:这次更新也是。)

AI 参与程度
润色
完全
不使用
给博客配一个桌面端后台:从 CLI 原型到轻阅集成
https://blog.142588.xyz/posts/blog-admin-panel/
作者
Watch Your Back
发布于
2026-09-13
许可协议
CC BY-NC-SA 4.0

评论

加载中…