Fallow:Rust 写的 TS/JS 代码库"体检"图分析器

Fallow
TypeScript
JavaScript
Rust
静态分析
开源
DX
2026/9/30
·

阅读时间: 大约 10 分钟

Fallow:Rust 写的 TS/JS 代码库”体检”图分析器

Fallow 在 vitest monorepo 上的 PR 门禁输出:循环依赖、重复、高复杂度函数与死代码一览

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
编码 Agentnpx 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 用一个固定的本地模型),同一份输入永远得到同一份输出,每个发现都有稳定指纹——这对”会让你构建失败”的工具是必要的可预测性。

在已有代码库上接入 fallow:作为 dev 依赖安装、内置 fallow/lsp/mcp 三个入口与 pre-commit 钩子

四、关键数据

以 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 时要注意它的商业化设计:

  1. 静态分析免费,运行时数据付费:README 明确”Everything else in this README is free”,而 Fallow Runtime 是可选付费层——它把真实生产流量里的热路径/冷路径证据合并进 health 与 audit 报告,用来判断”这段死代码删了会不会出事”。也就是说,免费版告诉你”没人 import 它”,付费版才能告诉你”它在生产里真的从没被调用过”。
  2. 纯语法路径有误报边界:默认快但不做类型解析,依赖 --type-aware 才能精确处理接口、基类、跨包 re-export;想要零误报就得接受更慢的模式。
  3. 它不替代 linter/编译器:官方反复强调 Fallow 与 ESLint/Biome/oxlint 互补,不做代码风格、不做类型检查,定位是项目级图分析。
  4. 基准有自家立场:74ms vs 2.01s 来自官方自己的 BENCHMARKS.md,且只在 preact 上赢、在 astro/TS 上落后,不能概括为”全面比 knip 快”。

六、优势与局限

优势:

  1. 零配置、单二进制、秒级出结果,Monorepo 一等公民(识别 npm/yarn/pnpm workspaces);
  2. PR 门禁只看新增问题,历史债不会让你永远卡 CI,落地阻力小;
  3. 覆盖维度广:死代码、重复、循环依赖、复杂度、架构边界、设计系统漂移一次跑完;
  4. 可预测:无 AI 混入核心分析、稳定指纹、typed JSON 输出、文档化退出码。

局限:

  1. 删除证据依赖付费 Runtime,免费版删死代码仍需人工确认;
  2. 默认语法路径有误报,精确分析要开 --type-aware;
  3. 年轻项目(示例版本号仍在快速迭代),规则集与生态仍在扩张;
  4. 不解决文件内规范与类型问题,不能取代 ESLint/tsc。

七、谁该用

  • 背负大量历史代码、想逐步还债的团队:audit 门禁让你只约束新增代码,不被 98 个老问题绑死;
  • Monorepo 维护者:想一眼看清跨包循环依赖与架构漂移;
  • 想给编码 Agent 配上”项目级地图”的人:agent install 让 Agent 复用同一套分析结果。

如果你的仓库很小、结构清晰,Fallow 的收益有限;但当项目长大到”没人敢删任何文件”时,这种把整仓库读成一张图、并只在 PR 上卡新增问题的工具,正是把重构从”大爆炸式”变成”持续小步”的关键基础设施。

参考来源