Fallow:Rust 写的 TS/JS 代码库"体检"图分析器
阅读时间: 大约 10 分钟
Fallow:Rust 写的 TS/JS 代码库”体检”图分析器

ESLint、Biome、oxlint 这些 linter 解决的是”这个文件写得规不规范”,TypeScript 解决的是”类型对不对”。但有一类问题它们都不管:整个仓库里哪些文件根本没人用、哪些函数被复制粘贴了几十遍、哪些模块形成了循环依赖、哪些地方已经复杂到一碰就碎。Fallow(MIT 协议,仓库 fallow-rs/fallow)定位就是这个空位——它是一个 Rust 编写的代码库智能(codebase intelligence)工具,把整个仓库读成一张图(模块、导出、依赖、函数、样式 token),再在这张图上做分析。一条 npx fallow 即可启动,不需要 TypeScript 编译器、不需要配置。本文基于其官方 README,分析它的能力边界、性能口径与商业模式。
一、背景:linter 之上的”项目级”盲区
linter 是文件级的:它一次看一个文件,所以能告诉你”这里用了 ==”,但看不到”这个文件从来没被任何地方 import”。死代码、跨文件重复、循环依赖、架构边界漂移,本质都是图结构问题,必须把全仓库作为一个整体才能发现。Fallow 官方把这件事讲得很清楚:格式化器问”这文件一致吗”、linter 问”这文件规范吗”、TypeScript 问”类型对吗”,而 Fallow 问”整个代码库健康吗”。
二、是什么:一个 Rust 二进制,跑在四个地方
Fallow 的核心是一个 Rust 二进制,不需要 Node 依赖、不需要先跑 tsc。它可以在四处运行,且共用同一份配置与同一套分析引擎:
| 场景 | 入口 |
|---|---|
| 终端 | npx fallow |
| Pull Request 门禁 | GitHub Action fallow-rs/fallow@v3 |
| 编辑器 | VS Code 扩展或 fallow-lsp |
| 编码 Agent | npx fallow agent install |
它还提供 npx fallow viz,生成一个交互式 HTML 项目地图,按健康度、重复、架构、死代码等视角切换。
三、技术机制:一张图 + 一组命令
Fallow 把分析拆成命令族,每个命令回答一个具体问题:
fallow audit(这次改动能安全合并吗):只对变更文件做门禁,输出 pass/warn/fail,只对本次改动引入的问题报错,历史遗留问题不计入门禁;fallow health:复杂度热点、0–100 健康分与 A–F 评级、重构目标,并结合 git churn 与代码 ownership;fallow dead-code/fallow fix:找出无人使用的文件、导出、类型、类与枚举成员、依赖,支持自动修复与 dry-run 预览;fallow dupes:在 JS、TS、CSS 以及 Vue/Svelte/Astro 组件区域里找复制粘贴的代码块;fallow guard/--boundary-violations:检查架构边界违规,内置 bulletproof、分层、六边形、feature-sliced 等预设;fallow security:按从入口点的可达性对安全候选排序(可选);fallow similar-code:找出”意图相同但写法不同”的函数,这是唯一用到本地模型的命令。
默认走纯语法(syntactic)的快速 Rust 路径,不需要 TypeScript;可选 --type-aware 模式做跨别名、re-export、跨包的精确符号识别,以消除接口与基类带来的误报。官方强调:分析器内部没有 AI(只有 opt-in 的 similar-code 用一个固定的本地模型),同一份输入永远得到同一份输出,每个发现都有稳定指纹——这对”会让你构建失败”的工具是必要的可预测性。

四、关键数据
以 README 中 fallow 3.30.0 在 vitest monorepo 最近 15 次提交上的 audit 为例:
| 指标 | 数值(官方示例) |
|---|---|
| 变更范围 | 73 个文件 vs HEAD~15 |
| 循环依赖 | 24 处(如 artifact.ts→run.ts→context.ts→artifact.ts,6 个环) |
| 重复 | 185 行(0.2%)跨 6 个文件 |
| 高复杂度函数 | 28 个(示例 runTest:圈复杂度 32、认知复杂度 47、203 行,标 CRITICAL) |
| 死代码 | 68 个 issue |
| 门禁排除的历史问题 | 98 个(不计入本次失败) |
性能方面,官方给出:在 preact 仓库上,Fallow 找死代码耗时 74ms,而 knip 6 需 2.01s;但同时官方也承认在 astro 与 TypeScript 仓库上 knip 更快(基准基于 fallow 2.100.0,方法见仓库 BENCHMARKS.md)。这是个诚实的对比——快是相对的,且随仓库类型变化。
五、评测与商业模式批判
读 Fallow 时要注意它的商业化设计:
- 静态分析免费,运行时数据付费:README 明确”Everything else in this README is free”,而 Fallow Runtime 是可选付费层——它把真实生产流量里的热路径/冷路径证据合并进 health 与 audit 报告,用来判断”这段死代码删了会不会出事”。也就是说,免费版告诉你”没人 import 它”,付费版才能告诉你”它在生产里真的从没被调用过”。
- 纯语法路径有误报边界:默认快但不做类型解析,依赖
--type-aware才能精确处理接口、基类、跨包 re-export;想要零误报就得接受更慢的模式。 - 它不替代 linter/编译器:官方反复强调 Fallow 与 ESLint/Biome/oxlint 互补,不做代码风格、不做类型检查,定位是项目级图分析。
- 基准有自家立场:74ms vs 2.01s 来自官方自己的 BENCHMARKS.md,且只在 preact 上赢、在 astro/TS 上落后,不能概括为”全面比 knip 快”。
六、优势与局限
优势:
- 零配置、单二进制、秒级出结果,Monorepo 一等公民(识别 npm/yarn/pnpm workspaces);
- PR 门禁只看新增问题,历史债不会让你永远卡 CI,落地阻力小;
- 覆盖维度广:死代码、重复、循环依赖、复杂度、架构边界、设计系统漂移一次跑完;
- 可预测:无 AI 混入核心分析、稳定指纹、typed JSON 输出、文档化退出码。
局限:
- 删除证据依赖付费 Runtime,免费版删死代码仍需人工确认;
- 默认语法路径有误报,精确分析要开
--type-aware; - 年轻项目(示例版本号仍在快速迭代),规则集与生态仍在扩张;
- 不解决文件内规范与类型问题,不能取代 ESLint/tsc。
七、谁该用
- 背负大量历史代码、想逐步还债的团队:
audit门禁让你只约束新增代码,不被 98 个老问题绑死; - Monorepo 维护者:想一眼看清跨包循环依赖与架构漂移;
- 想给编码 Agent 配上”项目级地图”的人:
agent install让 Agent 复用同一套分析结果。
如果你的仓库很小、结构清晰,Fallow 的收益有限;但当项目长大到”没人敢删任何文件”时,这种把整仓库读成一张图、并只在 PR 上卡新增问题的工具,正是把重构从”大爆炸式”变成”持续小步”的关键基础设施。