前端依赖治理全攻略:识别、删除、优化一步到位
一、背景
在长期迭代的前端项目中,package.json 里的依赖往往越来越多:
-
早期引入的库早已没人使用
-
一些三方包只是试用后遗留
-
甚至还混着几个版本相近的重复依赖
这些“无用依赖”看似无伤大雅,但它们会:
-
增加 node_modules 体积,占用磁盘和 CI 构建缓存
-
让 npm install / pnpm install 变慢
-
增加安全漏洞和维护成本
最近我在一个老项目上做了依赖治理,仅删除无用依赖,就让构建速度提升了 40%,打包体积减少 200MB+。 下面分享我完整的清理思路和实用脚本,希望能帮你也给项目来一场“依赖大扫除”。
二、技术选型
工具简介
depcheck 是一个 Node.js 依赖分析工具,用于扫描项目的 package.json 和源码,找出:
- 未使用的依赖(Unused dependencies)
- 缺失的依赖(Missing dependencies)
工具原理
读取项目根目录下的package.json,获取所有声明的依赖(dependencies、devDependencies),遍历项目目录下的源码文件(如 .js, .jsx,.ts,.tsx 等),查找所有的依赖引用方式,包括require('xxx')、import xxx from 'xxx'、import('xxx')某些工具函数调用等,通过静态分析(AST 解析)代码,提取出所有被实际引用的模块名。
为什么要用 depcheck
-
保持依赖清洁,减少项目体积
-
长期迭代项目中,会遗留一些不再使用的依赖(历史代码、功能下线未删除的依赖)
-
久而久之node_modules体积增大、CI/CD构建时间增加(install、build、以及job之间的缓存传递都会增加构建耗时)、安全漏洞风险
-
-
发现依赖缺失,避免运行时错误
-
有时代码中引用了某个包,但忘记在
package.json中声明(比如在全局安装过,或者依赖通过其他包间接引入) -
本地运行正常(因为缓存或全局安装)但是CI/CD 或新环境运行时报错
Cannot find module
-
-
提高构建与部署效率
-
冗余依赖会拖慢安装速度
-
清理以后会安装速度变快、构建产物变小、部署包体积也变小
-
-
降低安全风险
- 每新增一个包就会多一个安全风险,你永远不能控制一个包引用的其他依赖包
三、实战经验
实践流程
-
先全局搜索查看代码中是否有import、require()
-
运行pnpm ls 依赖包,判断直接依赖
- pnpm ls 没有输出,说明没有直接依赖
-
运行pnpm why 依赖包,判断间接依赖
- pnpm why输出一堆,说明又很多其他包间接依赖了它
-
全部判断无误,开始删除依赖项
-
每次只删一两个依赖,跑一遍测试,确保功能不受影响
-
全部完成以后判断哪些依赖包放在dependencies,哪些依赖包放在devDependencies
-
需要注意依赖一些babel包最好不要删,删除要谨慎,因为它可能通过配置文件等特殊方式引入的
安装&实战
安装
pnpm install -g depcheck
npx depcheck
depcheck运行结果如下
Unused dependencies
* antd-mobile-icons
...
Unused devDependencies
* @babel/preset-react
...
// 这里是项目本地模块的引用,比如一些别名会扫不到
Missing dependencies
* utils: .\src\services\index.js
* components: .\src\pages\index.tsx
...
实战
依赖分层治理
-
我们可以将分析结果分为三类
Unused dependencies 依赖整理、Unused devDependencies 依赖整理、Missing dependencies 整理,用以下模板来管理依赖的删除与运行结论 -
Unused dependencies 依赖整理、Unused devDependencies 依赖整理
| 包名 | 描述 | 历史负责人(方便追溯) | 删除结论 |
|---|---|---|---|
| antd-mobile-icons | antd mobile图标库 | xipiker | // 判断是否有间接依赖,没有则继续判断有没有直接依赖 pnpm ls antd-mobile-icons // 判断是由有直接依赖,没有则直接运行 pnpm why antd-mobile-icons // 运行完成后清除项目cache,重新跑以下看是否能启动成功 pnpm remove antd-mobile-icons && pnpm install && pnpm run start 结论:可以删除无之间&间接依赖,删除后已经重新运行 或者 无法删除,无法删除原因 |
| load-js | 动态加载外部js | xipiker | // 判断是否有间接依赖,没有则继续判断有没有直接依赖 pnpm ls load-js // 判断是由有直接依赖,没有则直接运行 pnpm why load-js // 运行完成后清除项目cache,重新跑以下看是否能启动成功 pnpm remove load-js && pnpm install && pnpm run start 结论:可以删除无之间&间接依赖,删除后已经重新运行 或者 无法删除,无法删除原因 |
Missing dependencies 整理
| 包名 | 描述 | 删除结论 |
|---|---|---|
| utils: .\src\services\index.js | 别名 | 不删 |
| components: .\src\pages\index.tsx | 别名 | 不删 |
分析汇总
| 原依赖 | 优化后依赖 |
|---|---|
| 依赖总数(XX) | 依赖总数(XX)删减XX个依赖包,占比XX% |
| pnpm install 命中缓存耗时≈XXs | pnpm install 命中缓存耗时≈XXs,减少XXs,占比XX% |
四、治理规约
-
git pipeline可以接入depcheck分析,定期推送分析结果
-
后续团队成员需要新增依赖包,需要集体评审严格把关
-
对于技术评审对依赖评估后,可能不稳定的包,必须写死版本号
-
在写测试demo时候没有用到的依赖直接删掉,别提交到release
五、结语
你现在的项目里有多少个依赖?不妨读完这篇文章后清点一下,看看能减掉多少。