接手一个遗留项目或者做代码评审的时候,最头疼的不是业务逻辑有多绕,而是代码里那些散落的 TODO、FIXME 注释——它们像地雷一样埋在几千个文件里,有的写着“后面要改”,有的写着“这里可能有 bug”,但没有人知道它们到底在哪、对应哪段逻辑、又堆积了多久。我在本地重度依赖一个 VS Code 插件叫 Todo Tree,它能把代码里所有 TODO、FIXME 之类的高亮注释自动扫描出来,整理成一棵可以点开跳转的“技术债清单树”。这篇文章就围绕 Todo Tree 展开,聊聊它的工作思路、核心配置、真实工作流和踩过的坑,适合正在做项目维护、代码重构、或者想把自己工作区里的注释债务看明白的开发者。
1. 项目整体设计与思路拆解
1.1 Todo Tree 到底解决了什么问题
先说结论:Todo Tree 是一个基于 VS Code 的高亮注释管理工具,核心能力是扫描当前工作区内所有代码文件,把符合规则的注释标签(默认是 TODO、FIXME、HACK 等)提取出来,按文件路径和标签类型组织成树状列表,显示在单独的面板里。点击列表项就能直接跳转到代码对应行,同时注释文本中的关键词会被高亮。
这个需求听起来小儿科,但真正写代码的人都知道,IDE 自带的问题面板只管编译错误和警告,根本不管注释里写的“待办事项”。代码里的 TODO 注释本质上是一种“给未来的自己留的口信”,可一旦项目大了、人员流动了,这些口信就成了信息孤岛。Todo Tree 做的事情就是把这些孤岛串联起来,变成一个可视化清单,让技术债无处可藏。
我最早接触这类需求的时候,用的是最笨的方法——全局搜索“TODO”,然后在搜索结果列表里一条条看。问题很明显:搜索结果把注释和正常的字符串混在一起,噪音大;没有按文件折叠,几百个结果滚半天;换一个标记词又得重新搜。Todo Tree 的核心思路就是用“约定优先”的方式解决这个痛点:把注释标签当作一等公民,用正则规则解析,再用树形结构组织,整个过程不依赖语言语义分析,只依赖文本匹配。
1.2 设计上高明在哪:文本解析而不是语义分析
Todo Tree 没有走重型路线。它没有尝试理解你的代码上下文,也没有建索引数据库,而是基于每个文件的文本内容按行扫描,用正则表达式匹配注释标记,然后统计结果。这在方法论上很像“日志采集”,而不是“代码理解”。
这个设计选择非常务实。如果走语义分析路线,那就得适配每种编程语言的注释规范,成本高不说,对动态语言来说准确率也很难保证。基于正则提取的方式有三个明显优势:
- 对语言无要求,无论是 JavaScript、Python、Go 还是 Markdown、配置文件,只要注释语法能被识别,就能扫。
- 扫描速度极快,因为只是字符串匹配,不涉及语法树,打开大项目也能很快渲染。
- 规则透明,用户可以通过修改正则表达式的配置,自定义哪些文本算“待办标记”,灵活性很高。
我在实际使用中明显感觉到,对比那些试图做“全局代码语义索引”的插件,Todo Tree 的响应速度是碾压级的。打开一个包含几千个文件的前端工程,面板几乎秒开,滚动也很顺滑,没有那种“等待索引完成”的焦虑感。
1.3 工作区范围与符号树的组织逻辑
Todo Tree 的面板默认按“文件路径”组织成树,每个标签在树里是一个叶子节点。你可以在“视图”面板里展开任意文件夹,看到该目录下所有匹配的注释,也可以按标签类型(TODO、FIXME)分组,甚至按标签颜色分组。这个树状结构的交互有点像文件资源管理器,只是展示的不是文件,而是“待办项”。
更深一层,Todo Tree 还利用了 VS Code 的“符号”能力——它能把 TODO 标签作为工作区符号处理。这意味着你可以通过 Ctrl+Shift+O(macOS 上是 Cmd+Shift+O)输入“TODO”来快速搜索整个工作区的标签符号,也可以在编辑器标题栏的面包屑里看到当前文件中有哪些待办标记。
我在维护一套老旧的电商后端服务时,就靠这个符号视图快速定位过一类很隐蔽的问题:某个数据迁移脚本里散落了十几个 TODO,注释写的是“一个月后需要清理临时表”。正常全局搜索也能搜到,但从符号视图点进去会直接聚焦到注释行,而且能看到函数上下文,排查效率高很多。
2. 核心配置解析与实操要点
2.1 安装之后先改这五个配置
Todo Tree 默认配置对大多数人已经够用,但它真正强大的地方在于自定义能力。下面是我每次在新环境里落地这个工具时必调的五个配置项,逐个说明用途和背后的逻辑。
第一,todo-tree.general.tags。这是最核心的配置,用来定义哪些标记算“待办标签”。默认值是["TODO", "FIXME", "HACK"]。我会把它改成["TODO", "FIXME", "HACK", "XXX", "BUG", "NOTE"],因为实践中很多人会写“XXX:这里逻辑有问题”,或者用“BUG”标注已知缺陷。“NOTE”也不是可留可不留,它往往能帮你看出代码里哪些地方被反复解释过——解释得越多的地方,往往越值得重构。
第二,todo-tree.highlights.defaultHighlight。这个配置控制高亮效果,里面的icon和foreground决定注释在代码里长什么样。我会把 FIXME 单独设置成黑底红字,让它比 TODO 在视觉上更刺眼。这种视觉权重划分对“技术债分级”很重要,你扫一眼代码,就能区分“紧急缺陷”和“后续优化”。
第三,todo-tree.general.autoRefresh。这个开关决定文件保存时是否自动刷新树。默认是开启的,但我建议在打开超大项目时把它关掉,改成todo-tree.general.autoRefresh: false,然后通过手动刷新按钮或者Todo Tree: Refresh命令(绑定快捷键shift+cmd+R)来控制刷新时机。原因是:文件保存触发全量扫描时,超大项目会出现明显的卡顿,关掉自动刷新后体验会稳定很多。
第四,todo-tree.filtering.includeHiddenFiles。默认情况下,Todo Tree 不会扫隐藏文件和node_modules、.git这类目录。这个默认行为非常正确,但要注意,如果你在项目里用了.env.example这样的隐藏配置文件,想要在里面标 TODO 让它被扫到,就需要显式打开 includeHiddenFiles。反之,如果发现扫描结果里混进了大量依赖包里的注释,就要检查是不是哪个配置把它带出来了。
第五,todo-tree.regex.regex。如果你对默认标签规则不满意,可以直接覆盖这个正则。默认值大致是(//|#|<!--|;|/\*|^|--)\s*($TAGS),它的意思是:在某些注释符号(比如//、#、<!--、;、/*、行首、--)后面跟着一个或多个空格,再跟上你的标签。我强烈建议不要轻易动这个正则,因为它要兼容多种语言非常繁琐,一旦写错会导致完全认不出注释。
2.2 标记的优先级与图标主题
除了“能不能扫到”,Todo Tree 还解决“扫到了怎么区分”的问题。面板里每个条目都会有图标,默认来自内置的图标集,但图标风格是可以换的。todo-tree.icons.theme这个配置可以选default、minimal、people等主题,后面几个是社区贡献的图标包。
图标不只是好看,更重要的是帮助你在视觉上快速分类。默认情况下,TODO 是一个绿色的小圆圈,FIXME 是一个红色的小三角,HACK 是一个黄色小锤子。如果你的项目自定义了很多标签,建议把标签对应的图标按“严重程度”分级——紧急用实心红色,普通用空心黄色,优化建议用灰色。这样展开树的时候,严重事项一眼就能跳出来。
还有一个很隐蔽但非常实用的小功能:标签的“匹配大小写”选项。todo-tree.general.tagGroups和matchCase配合,可以区分todo和TODO。有些团队约定小写 todo 只是普通备注,大写 TODO 才是正式待办,这种精细区分在统一代码规范的项目里很有价值。
2.3 过滤器的使用逻辑
Todo Tree 的过滤器很容易被忽略,但恰恰是把这工具推向高级用法的关键。todo-tree.filtering有三组配置:include、exclude、excludeGlobs。
先说include。它的作用是“只看某些目录”。如果你只想关注src目录下的 TODO,不想看test目录里的,可以加一条路径包含规则。我用过这个功能来应对“重构工作量评估”——把include限定在被重构模块的目录下,看到的结果就是这次重构真正需要处理的待办数量。
再说exclude。它用来排除特定路径,比如docs目录里大量“待补充说明”的 TODO 对你没有参考价值,直接排除。excludeGlobs则支持通配符模式,比如排除**/*.min.js这样的压缩文件,避免扫描产物的噪音。
这里有个实操心得:过滤器匹配的是路径字符串,不是 gitignore 规则。配置的时候要小心,一旦写错规则,比如路径分隔符写反了(Windows 是反斜杠,配置里要统一用正斜杠),匹配会全部失效。我踩过这个坑,最后把路径全部改成仓库根目录相对的写法,并且用/分隔,才恢复正常。
3. 实操过程与核心环节实现
3.1 从零到一:首次配置与面板布局
我以一个新接手的全栈项目为例,演示一遍 Todo Tree 的完整落地过程。项目是一个电商管理后台,前端 Vue、后端 Python Flask、数据库迁移脚本若干,总文件数大概 3000 个。
第一步,安装插件。打开 VS Code 扩展市场,搜索 “Todo Tree”,认准作者是Foojee的那个。安装完成后重启窗口,或者直接打开文件面板,就能看到侧边栏多出一个“TODO”树。首次打开时会自动扫描全工作区,一般几秒到几十秒不等,取决于文件数量和磁盘速度。
第二步,调整视图方式。在 Todo Tree 面板右上角的“视图”按钮(或者是视图切换的图标)可以选三种展示模式:按树形列表、按扁平列表、按标签分组。我推荐第一周先用“树形列表”,因为接手项目时你要先建立“哪些目录有债”的空间感;后面要清零某个具体类型的标签,再切到“按标签分组”。
第三步,打开设置 JSON。在设置界面搜todo,对所有Todo Tree前缀的条目点右上角的“在 settings.json 中编辑”,集中管理。这一步很关键,如果你用 UI 零散地改,回头很难复查到底调了哪些参数。
第四步,写入我常用的基准配置。下面这份配置可以直接抄走,适合大多数 Web 项目:
{ "todo-tree.general.tags": ["TODO", "FIXME", "HACK", "XXX", "BUG"], "todo-tree.highlights.defaultHighlight": { "icon": "check-circle", "foreground": "#CCCCCC", "background": "rgba(0, 0, 0, 0.1)" }, "todo-tree.highlights.customHighlight": { "FIXME": { "icon": "alert", "foreground": "#FFFFFF", "background": "#B71C1C", "gutterIcon": true, "rulerColor": "#B71C1C" }, "TODO": { "icon": "list", "foreground": "#2E7D32", "background": "rgba(46, 125, 50, 0.1)", "gutterIcon": true, "rulerColor": "#2E7D32" }, "HACK": { "icon": "tools", "foreground": "#F57F17", "gutterIcon": true }, "BUG": { "icon": "bug", "foreground": "#D32F2F", "background": "rgba(211, 47, 47, 0.2)", "gutterIcon": true } }, "todo-tree.general.autoRefresh": false, "todo-tree.filtering.enabled": true, "todo-tree.filtering.includeHiddenFiles": false, "todo-tree.filtering.excludeGlobs": ["**/node_modules/**", "**/dist/**", "**/build/**"] }第五步,验证效果。打开项目根目录下任意一个.vue文件,在 JavaScript 块里写一行// TODO:优化这里的表单校验逻辑,保存后手动执行Todo Tree: Refresh(命令面板里输入或绑定快捷键)。正常情况下面板里会出现这一条,并且文件行号旁边会出现绿色图标。
3.2 重构前如何使用 Todo Tree 做“排雷计划”
我实际用得最有价值的一个场景,是重构前用 Todo Tree 输出一份“排雷清单”。具体操作方式如下:
第一步,对整个工作区刷新一次 Todo Tree,然后把面板里的所有条目导出成清单。Todo Tree 自带“导出”功能(在面板右上角的三个点菜单里,可以选 Export),能生成一个 JSON 文件,里面包含路径、行号、标签、注释文本。我一般直接把它拉到一个表格工具里,按标签类型统计数量,先摸清“这个项目里有多少个 FIXME、多少个 HACK”。
第二步,按目录分组分析。把导出的 JSON 按一级目录聚合,重点看业务模块目录(如src/modules/order、src/modules/payment)的待办密度。密度高往往意味着这个模块改动频繁、质量欠稳定,是重构的重点候选对象。
第三步,给每个条目按“风险级别”人工打标。这一步不是 Todo Tree 自动做的,但它提供的注释原文和上下文跳转能节省大量阅读时间。我会快速浏览每个条目,把带有“崩溃”“空指针”“数据不一致”字眼的 FIXME 标为 P0,把“后续优化”“可以考虑”标为 P2。最后形成一个有优先级的行动表,比打开几十个文件漫无目的地找靠谱得多。
第四步,把排雷清单纳入迭代计划。每解决一个条目,就在代码里删掉对应的注释。这样当前工作区的 Todo Tree 条数会肉眼可见地变少,这种“清扫过程可视化”对团队信心有很大帮助,也让代码审查更有据可循。
3.3 结合 Git 分支做“注释差异审计”
Todo Tree 本身不直接和 Git 联动,但配合 VS Code 的源码管理面板,可以用一套简单的办法做“注释差异审计”:在你切换分支、合入新代码之后,快速看出这个分支比主干多了哪些 TODO。
操作思路是:先切到主干分支,刷新 Todo Tree,导出一份 JSON;切回特性分支,再刷新导出另一份 JSON;用 diff 工具对比两份文件。新增的条目就是这次改动的“新增技术债”,已删除的则是改动时顺手还掉的债。
我实际用过一次后很震撼。我们团队一个前端伙伴的合入请求代码量不大,但对比之后发现他新增了 11 个 TODO、2 个 FIXME,全部集中在刚适配的新接口逻辑上。评审的时候我们就有针对性地追问:“这几个 FIXME 什么条件下会触发?要不要合并前先解决?”如果没有这个对比流程,这些条目大概率会被忽略,等上线后变成线上问题排查时的盲区。
这个方法也适用于个人开发:每天下班前跑一次对比,把今天新增的 TODO 记到自己的任务笔记里,第二天开工就能明确优先级。
4. 常见问题与排查技巧实录
4.1 扫不到注释:正则与文件范围的坑
最常见的问题就是“我写了 TODO 但面板里没有”。我排查这个问题的顺序是:先在设置里确认todo-tree.general.tags是否包含你写的标签原词,注意大小写敏感性;再看文件是否被excludeGlobs排除;最后检查文件类型——Todo Tree 默认不会扫描gitignore中忽略的文件,也不会扫描二进制文件。
一个很容易忽视的细节是:Todo Tree 只认“注释”,不认字符串。比如你在console.log("TODO: 修复这个 bug")这段字符串里写了 TODO,默认情况下是扫不到的,因为正则要求 TODO 前面要有注释标记符。如果你硬要连字符串一起扫,需要改todo-tree.regex.regex,但我劝你千万别干这种事,噪声会大到你怀疑人生。
另一个隐蔽问题是“多行注释匹配”。Todo Tree 对/* TODO */这种跨行块注释的支持是有的,但只匹配块注释开头那一行。如果你把 TODO 写在注释块中间,比如:
/* * 这里做了一堆操作 * TODO: 后面要拆成函数 */这样也能扫到,因为正则匹配的是行首的*加空格加TODO。但如果你用了缩进或者注释风格不规范,比如*TODO:中间没空格,就认不出来了。遇到这种情况,我建议直接改代码规范,而不是魔改正则。
4.2 面板卡顿与自动刷新冲突
在超大项目里,Todo Tree 最常见的性能问题是:每次保存文件都会触发全量扫描,导致编辑器卡顿,甚至出现“Todo Tree 面板一直在转圈”。原因是autoRefresh默认开启,而扫描范围是当前整个工作区。
我的解决办法是不完全关掉自动刷新,而是配合“延迟刷新”。新版 Todo Tree 支持一个配置叫todo-tree.general.refreshDelay,单位是毫秒。把它从默认值调大一些,比如设成 1000~2000ms,保存文件后不会立刻全量扫描,而是等一小段时间再统一刷新。这个策略相当于给扫描加了“防抖”,在体验上既保留了自动更新,又避免高频保存时反复全目录匹配。
还有一个跟files.exclude相关的坑:如果项目里有动态生成的大文件(比如 lock 文件、快照文件、mock 数据),它们会被扫进 Todo Tree。我建议在.gitignore里忽略它们的同时,在 Todo Tree 的excludeGlobs里也同步加一条,毕竟插件不会自动读取 gitignore 规则。我后来养成一个习惯:每次给项目新增“生成物目录”,第一时间同步改 Todo Tree 排除项。
4.3 短横线符号和编码相关的边缘案例
Windows 环境有个常见的坑:路径里有中文或者空格,Todo Tree 的路径显示有时会异常,但跳转功能不受影响。这是因为树形展示用了相对路径拼接,如果仓库根目录名本身有特殊字符,面板里的根节点展示会不太对。我不建议为了这个去改配置,修复方法很简单:直接用“命令面板中的Todo Tree: Open File”,输入目标文件名就能定位。
另一个案例是“标签被注释符号截断”。比如 Python 里# TODO:这里要处理 None 值,如果整行前面有缩进,而正则模板里的注释符号匹配范围没有覆盖到缩进场景,就会漏扫。好在默认正则支持行首空白前缀,但如果你自定义了正则,务必在测试环境先拿几个不同语言的文件做验证。
我这里可以给一份按不同语言的标签写法规范表,都是实测能正常识别到 Todo Tree 里的:
| 语言类型 | 注释写法示例 | 是否可被默认识别 |
|---|---|---|
| JavaScript/TypeScript | // TODO: 优化渲染 | 是 |
| Python | # TODO: 修复边缘情况 | 是 |
| HTML | <!-- TODO: 补充文案 --> | 是 |
| CSS | /* TODO: 换变量 */ | 是 |
| YAML | # TODO: 调整超时时间 | 是 |
| Shell 脚本 | # TODO: 兼容 zsh | 是 |
| Java | // TODO: 捕获异常 | 是 |
如果你写的是//TODO:(冒号前没有空格),默认正则也能匹配,因为标签前后允许空格的写法是可选的。但为了团队统一和插件识别率,我强烈建议在代码规范里加上一条:“TODO 后面必须跟一个空格或冒号”。
4.4 树形面板消失或内容不全
有段时间我升级了 VS Code,发现 Todo Tree 面板不显示了,吓得以为是插件坏了。实际原因是新版 VS Code 改了活动栏图标的位置,需要手动把 Todo Tree 图标拖到侧边栏,或者通过“查看 -> 打开视图”手动找回。这种问题不是 Bug,但很干扰节奏,知道了就很好解决。
内容不全的情况,多半是todo-tree.general.scheme配置的问题。Todo Tree 能扫描所有 VS Code 能识别的文件 scheme,包括file(本地文件)、untitled(未命名临时文件),但默认不开 untitled。如果你在未保存的新文件里写了 TODO,想让它出现在树里,就得把scheme加上untitled。说实话我不太推荐这个用法,临时文件的注释进入技术债列表会污染清单,但确实有人需要,这里提一嘴。
5. 同类工具对比与边界思考
5.1 和 TODO Highlight、Code TODOs 的取舍
市面上和 Todo Tree 功能有重叠的插件不少,我在不同阶段都试过。简单对比一下:
TODO Highlight主要管“高亮显示”,它能让你在代码里看到醒目的 TODO、FIXME 标记色块,但没有树形列表、没有跨文件的汇总视图。如果你只是浏览单文件时不想漏掉注释,它更轻量。
Code TODOs走的是铿锵风格,把一个 TODO 关联到 GitHub Issue 或 GitLab Issue,适合完整工程闭环团队,但配置繁琐,还需要远程仓库权限。
Todo Tree 的定位介于两者之间:既有高亮,又有树形管理,而且不依赖远程服务。适合个人开发者,也适合没有强制“注释关联工单”的团队。我自己最终还是长期用 Todo Tree,因为它在“轻量”和“可控”之间平衡得最好——我不用被工具绑架去建一堆 Issue,也能在需要的时候导出一份清单。
5.2 Todo Tree 的边界:什么场景它不擅长
Todo Tree 不是代码质量检测工具,它不判断注释内容的质量,也不会主动提醒你“某个目录的 TODO 过剩”。它只是一个索引器,把注释变成清单。因此,如果团队里根本没人写 TODO 注释,装了它也不会变出一朵花。
另外,Todo Tree 的扫描单位是“文件”,不是“函数”。如果你想看到“某个函数里有几个 TODO”,只能靠跳转后肉眼观察,没有自动聚合到符号级别的能力。这在做细粒度技术债审计时会被折腾一下,但对我来说还好——把 TODO 导出后,再用脚本按函数上下文聚合也不是难事。
最后,它默认不做“时间提醒”。注释里写“两周内解决”是纯文本,Todo Tree 不会帮你设置 Deadline。真有这种强时效需求,应该配合任务管理工具,而不是指望 IDE 插件。这个边界想清楚,对工具的使用预期就不会跑偏。
6. 扩展玩法:让 Todo Tree 融入自动化工作流
6.1 把 Todo Tree 导出结果接入 CI 门禁
前面提到导出 JSON 功能,很多团队没意识到这可能是上工程化门禁的好苗子。你可以对导出的 JSON 做简单的统计:比如要求“每个新增 MR 里更新的 TODO 数量不得超过 5 个”,超出则提醒评审者注意。这个方案不需要引入额外的商业工具,只需要一段 Node 脚本或者 Python 脚本解析导出文件。
我在一个半夜上线事故后给团队搭过类似的“技术债水位线”脚本:每周一早上扫描主干分支的 Todo Tree 导出结果,把数量做成趋势图。这条线不卡发布,但能让管理者看到债务在涨还是跌。人都有惰性,当看到自己手写的 TODO 出现在周报图表里的数据点位上,整改意愿会明显提升。
6.2 配合代码模板,规范注释写法
还有一个小窍门:在代码片段(Snippet)里固化 TODO 注释格式。比如在 VS Code 的用户代码片段里,为 JavaScript 配置一个tt前缀,自动展开成:
// TODO: [$DATE] $CURRENT_TIME 需要完成的内容描述为什么要带日期?因为 Todo Tree 的标签本身不记录时间,日期可以帮助你在审计时快速判断这条注释“堆积了多久”。这是我个人认为最有价值的一个自定义扩展。配合todo-tree.highlights.customHighlight对超过一定年份的 TODO 做特殊颜色,就能形成“老龄化负债”的视觉冲击。
当然,更酷一点的方案是写一个 VS Code 扩展扩展,或者用 GitHub Actions 每周两次自动跑一个 CLI 版的扫描脚本,但那就是另一个项目的范畴了。Todo Tree 的价值恰恰在于它是“最后一公里”的呈现层:无论注释是哪里产生的,它都能及时反映到开发者的操作界面上。
7. 我的最终使用习惯与个人建议
到这里,Todo Tree 能做的事已经聊得差不多。我个人在使用中最依赖的组合是:关闭自动刷新,手动用shift+cmd+R控制刷新;每个周末花十分钟看一下 FIXME 数量有没有增加;每次重构一个模块,都会先导出一份 TODO 清单作为行动基线。
还有一个小心得想分享:别为了让面板“好看”而疯狂自定义标签和图标。标签太多会稀释注意力,我给团队定的红线是只允许五个标签:TODO、FIXME、HACK、BUG、NOTE。颜色控制在三档,红黄灰。工具本身提供强大的自定义能力,但使用上一定要做减法,否则等于把自己的眼力折腾进另一个泥潭。
踩过几次坑之后,我慢慢理解了一个道理:技术债从来不会因为你不看就消失,也不会因为一个插件就清零。Todo Tree 能做的,是把“我不知道这里有问题”变成“我知道这里有七个问题”。用好它的关键,不在于研究多少配置项,而在于把它纳入你自己的开发闭环——刷新、查看、导出、清理。坚持半年之后,你再看自己的工作区,那种清单上的条目越来越少的感觉,比任何代码指标都更让人踏实。