0
0

给 JavaScript 项目清理死代码前,我会先用 Knip 把入口、依赖和导出账本跑出来

代码库变大以后,真正拖慢维护的常常是那些没人敢删的旧文件、已经换掉却仍留在 package.json 里的依赖、以及只在历史分支里存在过的导出。Knip 的定位很贴近这个问题:它从项目入口、工具配置和工作区结构出发,报告未使用文件、依赖、导出、未列明依赖和循环依赖等问题。我的用法会先把它当成一张可复核账本,再决定哪些可以删,哪些需要补配置。这样清理动作有证据,评审也更容易判断风险。

Knip 项目清理流程示意图

从项目入口、模块图分析到未使用文件、导出、依赖和 CI 报告的流程示意 来源:Codex image generation

先跑报告,再拆事实源

第一次接入时,我不会一口气追求清零。Knip 的 first cleanup 文档建议先缩小输出,例如只看少量问题或只包含 files 类型。这个顺序很重要,因为未使用文件通常会带出一串后续现象:文件删掉后,它的导出、测试辅助函数和导入的依赖也可能从报告里消失。先从顶部处理,可以避免对同一条废弃链路重复判断。

我通常会把结果分成四类。第一类是确定无引用的文件,可以进入删除候选。第二类是未使用导出,需要判断它是公开 API、测试夹具,还是内部历史遗留。第三类是依赖问题,unused dependency 可以考虑移除,unlisted dependency 反而要补进 package.json,避免依赖解析靠传递安装侥幸成功。第四类是 reachability gap,例如框架约定路由、插件读取配置、动态 import 或生成代码,这类问题要通过 entry、project、插件配置或忽略规则补齐上下文。

Monorepo 里先画工作区边界

在 monorepo 中,Knip 会围绕 workspace 工作。官方文档说明,它可以从 package.json workspaces、pnpm-workspace.yaml 和 Knip 配置里读取工作区,并要求 workspace 目录有 package.json。这里最容易踩坑的是把根目录配置当成全局规则。对于有 workspaces 的项目,root 级的 entry 和 project 会被忽略,要放到名为 . 的根 workspace 下。

所以我会先让 Knip 无配置跑一遍,观察它识别了哪些工作区、启用了哪些插件,再补最小配置。共享包、脚本目录和应用目录要分开看,因为一个 workspace 的导出可能被另一个 workspace 使用。需要只看某个包时,用 --workspace 过滤;需要隔离生产依赖时,再配合 production 或 strict 模式。这样报告才不会把跨包引用误判成没人使用。

CI 里只守新增债务

清理工具一旦接进 CI,策略要克制。Knip 的 CI 文档写明,存在问题时进程会以 code 1 退出,也建议可使用 cache、reporter,并考虑同时跑默认模式和 production mode。我的做法是先把历史报告固化成一轮清理任务,在 CI 里只拦新增的未使用文件、未列明依赖和关键导出问题。等基线收敛后,再逐步提高规则。

落地时可以从 npm run knip -- --include files,dependencies 开始,把输出接到 PR 检查。对大型仓库,先让报告在主分支上稳定一两周,再启用 fail。这样团队会把 Knip 当成维护入口,减少一次性大扫除式推进。

可复用经验

Knip 最有价值的地方,是把“这段代码还能不能删”变成可以追踪的工程证据。入口文件、项目文件、工作区、依赖清单和 CI 报告共同构成事实源。只要先把 reachability gap 补清楚,再把自动修复和人工复核分层,死代码清理就能从偶尔想起来做,变成每次合并都会守住的项目卫生习惯。

主要来源

Knip 官方网站

Knip First Cleanup

Knip Monorepos & Workspaces

Knip CLI Arguments

Knip Using Knip in CI

Knip Issue Types

Knip GitHub 仓库

评论