Lerna多项目场景下安装外部包并统一依赖版本的正确方法
Lerna Monorepo 统一外部依赖版本最优方案
以下是不同方案的对比和最优实践说明:
你提到的两种方案的优缺点
方案1:外部依赖安装在my-common并重新导出
// my-common 中导出 import joi from "joi"; export {joi}; // 上层项目引入 import {joi} from 'my-common';
- 适用场景:需要对
joi这类公共依赖做二次封装(比如统一默认参数、添加自定义校验规则),且所有上层项目都使用封装后的能力 - 优势:天然保证所有上层项目使用的依赖版本完全一致,封装逻辑仅需维护一份
- 劣势:
- 灵活性差,上层项目如果需要使用原生依赖未被导出的API会受限制
- 迭代成本高,后续要升级依赖版本必须先升级my-common,还要同步兼容所有依赖my-common的项目
- 容易产生隐式依赖问题:如果上层项目偷偷直接引入了依赖但自身没声明,刚好my-common安装了该依赖,本地开发可能正常运行,上线打包才会报错
方案2:外部依赖分别安装在三个项目中
- 优势:各项目依赖声明清晰,不存在隐式依赖问题
- 劣势:很容易出现版本不一致的情况,比如my-Main-A装了
joi@17.7、my-common装了joi@17.9,最终打包会生成两份joi代码,不必要地增大产物体积
最优统一版本方案:Lerna 依赖提升 + 根目录强制锁版本
用Lerna官方提供的依赖提升能力,既可以保证版本统一,又不会损失灵活性:
- 先在
lerna.json中开启依赖提升配置:
{ "npmClient": "npm", "command": { "bootstrap": { "hoist": true } } }
如果使用pnpm作为包管理器,在pnpm-workspace.yaml中配置public-hoist-pattern字段即可达到相同效果。
2. 所有需要用到该依赖的子包(my-common、my-Main-A、my-Main-B),都在各自的package.json中声明依赖,版本号统一使用同一规则(比如统一写^17.9.0)
3. 执行依赖安装后,所有子包的joi都会被提升到根目录的node_modules中,整个项目只会存在一份joi,完全保证版本一致。
强化版本统一的优化方案
如果担心子包开发者不小心写错依赖版本,可以在根目录配置强制锁定规则:
- pnpm场景:在根目录
package.json中添加overrides配置
{ "pnpm": { "overrides": { "joi": "17.9.2" } } }
- yarn场景:在根目录
package.json中添加resolutions配置
{ "resolutions": { "joi": "17.9.2" } }
配置后不管子包声明的依赖版本是什么,最终都会被强制安装指定版本的依赖,彻底避免版本不一致问题。
特殊场景选择建议
- 如果确实需要对公共依赖做统一封装:可以在上述最优方案的基础上,在my-common中做封装导出,上层项目按需选择使用封装后的版本或者原生版本
- 如果只有my-common用到该依赖,上层项目完全不需要直接调用依赖的API:仅需要在my-common的
package.json中声明依赖即可,上层项目不用重复声明
内容的提问来源于stack exchange,提问作者Or Yaacov
相关产品推荐
相关产品推荐

