在模块化开发中,我们常常与各种依赖打交道:dependencies、devDependencies、peerDependencies 等等。错误的声明可能导致流水线失败,或者是偶现的、难以调查的 bug,甚至导致整个平台界面空白。
本文尝试说明 Brick Next 架构下的依赖管理方法及其背后的原因。在阅读本文前,建议先阅读 npm 官方关于依赖声明的文档。
TL;DR
- 在所有 Lerna 管理的项目中:
- 开发设施依赖(包括测试、构建等工具)都声明在项目根目录的
package.json的devDependencies。
- 开发设施依赖(包括测试、构建等工具)都声明在项目根目录的
- 在由
create-next-repo新建的仓库中:- 如果有某个包依赖了其它仓库(例如
brick-next)中的构件包、模板包,需要在仓库根目录中的devDependencies中额外声明它们。
- 如果有某个包依赖了其它仓库(例如
- 在
@bricks/*包中:- Custom Templates 依赖的其它构件包声明在
peerDependencies,版本号需要按 semver 正确声明; - 对
@next-dll/*的依赖声明在peerDependencies,并且版本号只需要填写*; - 其它依赖声明在
devDependencies。
- Custom Templates 依赖的其它构件包声明在
- 在
@micro-apps/*或@templates/*包中:@bricks/*和@templates/*依赖声明在peerDependencies;- 其他依赖声明在
devDependencies。
- 其他包(例如
@libs/*)中:- 对
@next-dll/*的依赖声明在peerDependencies,并且版本号只需要填写*; - 其他依赖声明在
dependencies。
- 对
- 所有包不需要声明依赖
@next-core/bricks-dll和@next-core/bricks-types,它被声明在项目根目录中。 - DLL(包括
@next-core/bricks-dll和@next-dll/*)中已包含的依赖不需要再显示声明了。
Why
我们先看不同类型的依赖有什么不同的表现:
dependencies会被递归安装,其它类型的依赖则不会。例如A依赖了B,B依赖了C,那么在A包中执行yarn时,BC都会被安装。peerDependencies不会被自动安装。lerna version发布版本时,会自动更新内部子包之间的dependencies及devDependencies的版本。
结合上述内容和我们的需求,就不难理解我们如何管理 Brick Next 的依赖了。
Q: 为什么 DLL 包含的依赖不需要再显示声明了?
A: dependencies 会被递归安装,冗余的声明一方面难以维护,另一方面容易造成版本差异导致问题。
Q: 为什么 @micro-apps/* 依赖的 @bricks/* 声明在 peerDependencies 并且还需要手动更新其依赖版本?
A: 小产品对构件库、模板库的依赖需要同步到 EasyOps 的包依赖关系中(package.conf.yaml),因此需要声明该依赖(我们的打包工具会扫描这些依赖生成一份 package.conf.yaml)。而我们期望构件库能保持兼容性,小产品对构件库的依赖版本不能始终跟随版本发布而更新,因此只有声明在 peerDependencies 中才不会被 Lerna 自动更新。也因此在小产品需要使用构件的新特性时,需要主动更新其依赖版本。
Q: 为什么 @bricks/* 的 Custom Templates 依赖的其它构件包要声明在 peerDependencies 中?
A: 如果 Custom Templates 中使用到了其它构件包的构件,那么这些依赖需要同步到 EasyOps 的包依赖关系中(package.conf.yaml),更多详情请参考上一条 Q/A。
Q: 为什么 @bricks/* 的其它依赖声明在 devDependencies?
A: @bricks/* 不会像 @libs/* 一样被 import 使用,我们只消费它生成的制品文件,因此它的依赖只在开发时有用。
Q: 为什么 @bricks/* 需要主动声明对 @next-dll/* 的依赖并放在 peerDependencies 中?
A: @bricks/* 被加载前需要按需加载用到的 @next-dll/*,所以需要有地方声明它们;另一方面,我们不希望 @next-dll/* 更新时也触发 @bricks/* 更新,所以放置到 peerDependencies 中。
Q: 为什么 @libs/* 的普通依赖都声明在 dependencies?
A: @libs/* 和我们日常使用的普通第三方库一样,会被 import 并在打包时整体编译,因此需要它的依赖及其依赖的依赖都被正确地安装在 node_modules 中。
Q: 为什么在由 create-next-repo 新建的仓库中,需要在仓库根目录中的 devDependencies 中额外声明构件包、模板包的依赖?
A: 因为 @micro-apps/* 对构件包、模板包的依赖基于这些包声明的构件列表、模板列表,所以需要在仓库中安装这些包才能完成相关校验和检查。而之前的 brick-next 大仓库模式下这些包都在本地,所以不需要声明及安装。