工程提炼:从 Folo 搬走什么
一、先把产品模型画清楚
Folo 最值得借鉴的不是某个库,而是它把 Feed、Subscription、List、Inbox、Entry、Summary、Translation 和 Chat 分成不同语义。领域模型一旦混乱,跨端复用只会把混乱放大。
二、依赖漏斗优于“共享一切”
共享包不是越多越好。共享层应该向下依赖稳定协议,平台壳层向上组合它们。最值得保留的边界是:
外部协议 -> Morph -> 领域 Model -> Store/DB -> UI selector -> 页面
每一层都能单独测试,也能在协议变化时收敛影响范围。
三、本地优先的四条纪律
- 本地 DB 是可恢复投影,不是随手的缓存;
- Store 是当前会话的即时投影,不替代持久化;
- 远端 API 是跨设备事实来源,但 UI 不必等待每次确认;
- 派生结果(摘要、翻译、Readability)永远可回退、可重建。
四、平台薄壳的真正难点
“业务共享、平台适配”听起来简单,真正难的是识别跨平台边界:
- DB driver 不同,但 schema 相同;
- Router 语义相同,但 history strategy 不同;
- Auth 语义相同,但 Cookie/secure storage 不同;
- UI 信息相同,但 DOM/RN 手势与虚拟列表不同;
- 发布目标相同,但 Forge/EAS/OTA/Pages 不同。
应当把这些差异明确命名、集中实现,而不是让条件分支渗入所有业务文件。
五、流式与后台能力需要 durable state
AI Chat、播放器、同步、OTA 下载、推送和后台任务都有“页面卸载后仍在继续”的可能。它们必须有 controller、状态枚举、错误结果、重试/取消语义和持久记录。只靠 React effect 和临时变量,无法覆盖移动端挂起、桌面重启和网络抖动。
六、发布系统要像业务系统一样可观测
版本、渠道、runtime、制品和策略之间是关系图。发布脚本应提供明确输入、不可变引用、幂等上传和可回滚指针。Folo 把平台 tag、OTA manifest、R2/GitHub 资产和同步端点串起来,正是把“交付”变成系统模型。
七、如果重写 Folo,最先改哪里
以下是基于源码阅读的改进方向,不代表上游项目问题:
- 为 Store action 统一记录 mutation 来源和版本,减少陈旧请求覆盖的隐式规则;
- 把 client-sdk → local Model 的 Morph 映射按领域文件拆得更细,便于协议升级审查;
- 为 DB 重建策略显式区分“可丢失缓存”和“不可丢失本地变更”;
- 为 SSR server/client 包边界增加更严格的 lint 或构建检查;
- 为 release graph 生成一份机器可读的兼容性矩阵;
- 为 AI/后台任务统一抽象 cancellation、retry、trace 和 durable status。
八、最后的阅读框架
看一个大型跨端项目时,可以重复使用这六个问题:
- 数据的事实来源在哪里?
- 哪一层把外部协议翻译成本地语义?
- 哪些状态需要跨重启保存?
- 哪些能力需要跨页面继续运行?
- 平台差异被集中在哪些文件?
- 发布产物如何证明、分发和回滚?
只要这六个问题有清晰答案,目录再大也能被拆成可验证的链路。