Monorepo中加载关联包时如何忽略开发依赖避免多lib实例?
问题:Monorepo插件共享依赖的单副本加载需求
我们维护着一个存储JavaScript库(下称lib)插件的Monorepo仓库,lib本身不属于该仓库,仓库通过Lerna管理。所有插件和lib一样均发布为NPM包,每个插件都将lib同时声明为peer依赖和dev依赖,部分插件还存在互相依赖的情况。
运行lerna bootstrap后,仓库的简化结构如下:
plugins/ ├─┬ a/ │ ├── index.js │ └─┬ node_modules/ │ ├─┬ lib/ │ │ └── (... 内容省略) │ └─┬ @lib/ │ └── b@ -> ../../../b └─┬ b/ ├── index.js └─┬ node_modules/ └─┬ lib/ └── (... 内容省略)
注:相互依赖的插件由Lerna创建符号链接,每个插件因lib是dev依赖而拥有独立的lib副本。
plugins/a/index.js代码如下:
import * as lib from 'lib'; import * as b from 'b';
plugins/b/index.js仅包含:
import * as lib from 'lib';
由于lib内部维护着状态,加载plugins/a/index.js时,a和b会各自加载独立的lib副本,导致依赖两者共享同一内部状态的测试全部失败。
需要说明的是,NPM包用户不会遇到这个问题——因为lib是@lib/a和@lib/b的peer依赖,正常使用时用户只会安装一个lib副本。问题仅出现在本地开发/测试阶段:lib作为b的dev依赖被安装,且该副本会被优先加载。
是否有办法让b作为a的依赖被加载时,不使用自身dev依赖的lib副本,转而复用a的lib副本?
此前我们通过Webpack为每个测试套件构建独立包来规避这个问题,对应的webpack.config.js配置如下:
{ resolve: { alias: { lib: path.resolve(fs.realpathSync(process.cwd()), 'node_modules/lib'), }, // ... 其他配置 } // ... 其他配置 }
该配置会强制所有import 'lib'的操作都加载当前测试插件(如plugins/a/node_modules/lib)的副本,但存在两个明显缺点:
- 最紧急的问题:该配置会导致Webpack忽略
lib的package.json中新增的exports字段,引发导入错误(尤其是子路径导出场景)。我尝试过设置alias: {lib: 'lib'},希望既能强制使用单一副本又不破坏常规Node模块解析规则,但没有效果。 - 必须先打包代码和测试才能运行,速度远慢于直接在Node.js中执行测试。
内容的提问来源于stack exchange,提问作者cpcallen
相关产品推荐
相关产品推荐

