年久失修!monorepo依赖管理失控补救方法
背景
开发monorepo项目时,因为文件结构较为复杂,时间久了往往会出现一些在所难免的问题,导致项目冗余度高,性能差,主要分为以下几类问题:
-
依赖管理不当,项目中存在大量重复依赖,无用依赖
-
存在多个不同版本的同一包
-
合码后pnpm-lock被忽略更新,导致团队开发时版本冲突
复现场景:
大量无用依赖和重复依赖怎么来的?
无用依赖(Unused Dependencies)
原因:
-
依赖未清理:项目中可能有一些包已经不再使用某些依赖,但没有及时从
package.json
中删除这些不再使用的依赖,导致它们被保留在项目中。 -
历史包依赖未清理:在开发过程中,如果有些包或者模块被拆分、重构或删除,之前的依赖可能仍然保留在
package.json
中,但这些依赖已经不再被任何代码实际使用。
场景示例:
假设原来项目中有包 C 和 D,其中包 C 使用了 axios
,但后来包 C 被拆分成两个小模块,且这两个模块中都不再使用 axios
了。此时 axios
依赖依然留在包 C 的 package.json
中,但实际上不再被任何代码使用。
// package.json of C (已不再使用 axios) { "dependencies": { "axios": "^0.21.1" } }
依赖版本不一致(Version Inconsistency)
原因:
-
不同子包依赖不同版本的同一个库:如果不同的子包依赖同一库的不同版本,pnpm 会倾向于安装多个版本,以避免版本冲突。这可能会导致在 monorepo 中出现多个版本的相同库,增加了冗余。
场景示例:
如果包 A 和包 B 都依赖 react
,但版本不同,pnpm 可能会安装两个版本的 react
,这会导致重复依赖。
// package.json of A { "dependencies": { "react": "^18.0.0" } } // package.json of B { "dependencies": { "react": "^17.0.0" } }
在这种情况下,pnpm
会将 react
18 和 17 的版本都安装到 node_modules
中。
pnpm 的 Hoisting 设置问题
原因:
-
Hoisting 配置不当:pnpm 默认使用 hoisting(提升)来将共享的依赖提升到根目录的
node_modules
中。如果 hoisting 配置不当,某些依赖可能不会被提升到根目录,而是被分散在各个子包中,从而导致重复的依赖和包体积冗余。
场景示例:
如果 pnpm
的 workspace 配置中,某些依赖没有正确提升到顶层,可能会导致每个子包都各自安装一份相同的依赖,而不是通过提升机制共享依赖。
// pnpm-workspace.yaml packages: - 'packages/*' - 'libs/*' hoist: - 'react' - 'lodash'
如果 react
和 lodash
在所有子包中都使用相同版本,pnpm 应该将它们提升到顶层。如果没有正确配置或不一致的配置,会导致重复安装。
忽视 Workspace Dependency(未共享依赖)
原因:
-
跨包依赖未共享:如果某些子包之间的依赖没有共享,而是每个包都独立安装,可能导致重复安装和依赖不一致。例如,如果包 A 和包 B 都使用了包 C,但各自独立地安装了包 C 而没有通过 workspace 管理共享这些依赖,就会导致冗余依赖。
场景示例:
假设包 A 和包 B 都依赖于包 C,但它们没有在 pnpm-workspace.yaml
中正确配置工作区共享,导致包 A 和包 B 都安装了包 C。
// package.json of A { "dependencies": { "C": "^1.0.0" } } // package.json of B { "dependencies": { "C": "^1.0.0" } }
如果没有通过 workspace 共享,而是让每个子包独立安装依赖,C
会在每个包中重复安装。
pnpm-lock被忽略更新
pnpm-lock是什么?忽略他有什么后果?可以参考我的另外一篇文章:pnpm.lock.yaml,看似无关紧要,实则······
如何解决问题(手动)
1. 清理无用依赖
步骤:
-
手动检查和删除无用依赖:检查每个包的
package.json
,确保只保留当前实际需要的依赖。如果发现某些依赖不再使用,手动删除它们。 -
使用工具自动检测无用依赖:可以借助一些工具自动检测项目中的无用依赖,避免遗漏。
-
depcheck
:一个常用的工具,它可以帮助找出未使用的依赖和丢失的依赖。npm install -g depcheck depcheck
-
npm-check
:另一个有用的工具,它不仅能检查无用依赖,还能检查过时的依赖。npm install -g npm-check npm-check
-
操作:
-
删除
package.json
中未使用的依赖,并在代码中确认移除相关的导入语句。 -
更新
pnpm-lock.yaml
文件,确保没有残留的冗余依赖。
2. 解决版本不一致
步骤:
-
统一版本管理:确保所有子包使用相同版本的核心依赖,避免出现多个版本的冲突。如果子包依赖同一个库的不同版本,可以选择统一版本或使用
resolutions
来强制指定版本。// 根目录的 package.json { "resolutions": { "react": "^18.0.0", "lodash": "^4.17.21" } }
-
检查
pnpm-lock.yaml
:确保pnpm-lock.yaml
中的依赖版本一致,手动或通过pnpm install
重新生成lock
文件。
操作:
-
执行
pnpm install
重新整理依赖,确保版本一致性。 -
使用
pnpm list
检查项目中安装的依赖树,确认是否有重复版本的依赖。
3. 优化 pnpm 的 Hoisting 设置
步骤:
-
配置 Hoisting 规则:确保
pnpm
的工作区配置正确,避免重复依赖。可以通过调整pnpm-workspace.yaml
中的hoist
配置来实现依赖的提升。// pnpm-workspace.yaml packages: - 'packages/*' - 'libs/*' hoist: - 'react' - 'lodash'
上面的配置会确保
react
和lodash
等共享依赖被提升到根目录的node_modules
中,避免重复安装。 -
避免不必要的 Hoisting:虽然 Hoisting 有时能解决问题,但过度提升可能会导致某些包的版本不兼容。在某些情况下,避免将某些依赖提升到根目录可能更有利于避免版本冲突。
操作:
-
通过
pnpm install
更新依赖,确保依赖被正确提升。 -
使用
pnpm list --depth 3
等命令检查是否有不必要的重复安装。
4. 使用 Workspace 共享依赖
步骤:
-
正确配置工作区依赖:确保
pnpm-workspace.yaml
中的各个包正确配置共享依赖,避免包之间的重复安装。例如,如果 A 和 B 包都依赖 C,确保通过workspace
来共享这个依赖。// pnpm-workspace.yaml packages: - 'packages/*' - 'libs/*'
-
集中管理依赖:将通用依赖(如 React、Lodash 等)移动到根
package.json
中,确保它们在所有包之间共享,而不是每个子包单独安装。
操作:
-
使用
pnpm install
执行工作区依赖的统一安装,确保共享依赖被正确配置。
5. 更新 pnpm-lock 文件
步骤:
-
重新生成
pnpm-lock.yaml
文件:在很多情况下,pnpm-lock.yaml
文件可能会被忽略更新,导致团队开发时出现版本冲突。定期清理和更新pnpm-lock.yaml
文件,确保其中的依赖是最新且一致的。pnpm install --frozen-lockfile
-
使用
pnpm audit
检查锁文件:运行pnpm audit
可以检查项目中的依赖漏洞和潜在的安全问题,确保锁文件和依赖是最新的。
操作:
-
删除
node_modules
和pnpm-lock.yaml
,然后重新执行pnpm install
。 -
使用
pnpm update
更新所有依赖并确保锁文件与package.json
一致。
6. 定期维护和监控
步骤:
-
定期清理:定期执行
pnpm prune
命令,清理不再需要的依赖,保持依赖树干净。pnpm prune
-
监控依赖:使用
pnpm outdated
定期检查过时的依赖,并及时更新。pnpm outdated
-
添加自动化检测:为项目添加 CI/CD 流水线,定期运行依赖检查工具(如
depcheck
、npm-check
),在代码提交前自动检测和清理无用依赖。
操作:
-
在 CI 中集成依赖管理工具,定期检测和清理冗余依赖。
如何解决问题(自动化)
1. GitHub Actions CLI 示例
这个 GitHub Actions 配置脚本将帮助你自动化清理无用依赖、更新依赖版本、优化 pnpm-lock.yaml
文件等工作。
不知道什么是 GitHub Actions,可以看我另外一篇文章: github actions--最好的打工仔,帮你干脏活累活
GitHub Actions 配置文件 ci.yml
name: zhuozhuoのCI #触发条件 on: push: branches: - dev-ywz pull_request: branches: - dev-ywz #定义工作流中的任务 jobs: depcheck: runs-on: ubuntu-latest #指定工作流运行的系统 steps: - name: Checkout code uses: actions/checkout@v2 - name: Set up pnpm uses: pnpm/action-setup@v2 with: version: 9.12.3 - name: Install dependencies run: pnpm install - name: Run depcheck to find unused dependencies run: | npx depcheck --ignore-path=pnpm.lock.yaml continue-on-error: true - name: Report unused dependencies run: | echo "depcheck执行成功" if [ -f "depcheck-report.txt"]; then echo "auv,您这儿有没用的依赖" cat depcheck-report.txt exit 1 fi version-consistency: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 - name: Set up pnpm uses: pnpm/action-setup@v2 with: version: 9.12.3 - name: Check and fix version consistency run: | echo "version-consistency执行成功" pnpm install --prefer-offline --frozen-lockfile # 前面执行了强制操作,audit兜底 pnpm audit lockfile-updata: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 - name: Set up pnpm uses: pnpm/action-setup@v2 with: version: 9.12.3 - name: Set up pnpm run: pnpm install - name: Clean upp unused dependencies run: pnpm prune - name: Update lock file run: | echo "lockile-update执行成功" git config --global user.email "3098448071@qq.com" git config --global user.name "PaiduiXiaowangzi" pnpm install git add pnpm-lock.yaml git commit -m'gh自动更新了 pnpm-lock' git push dependencies-update: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 - name: Set up pnpm uses: pnpm/action-setup@v2 with: version: 9.12.3 - name: Install depencies run: | pnpm install - name: Update outdated dependencies run: | echo "dependencies-update执行成功" pnpm outdated pnpm update pnpm test - name: Commit update code #上面成功了才执行 if: success() run: | pnpm add . pnpm commit -m'gh自动更新依赖'
说明:
-
depcheck:检查项目中的无用依赖,并报告,如果有无用依赖,CI 会失败,提醒开发者清理。
-
version-consistency:通过
pnpm audit
检查依赖版本的一致性,并确保所有子包使用相同版本的依赖。 -
lockfile-update:清理无用依赖并确保
pnpm-lock.yaml
文件是最新的,避免出现版本冲突。 -
dependency-update:检查并更新所有过时的依赖,确保项目始终使用最新的依赖版本。
原文地址:https://blog.csdn.net/a3098448071/article/details/144387063
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!