Skip to main content

Brick Next 的依赖管理

在模块化开发中,我们常常与各种依赖打交道:dependenciesdevDependenciespeerDependencies 等等。错误的声明可能导致流水线失败,或者是偶现的、难以调查的 bug,甚至导致整个平台界面空白。

本文尝试说明 Brick Next 架构下的依赖管理方法及其背后的原因。在阅读本文前,建议先阅读 npm 官方关于依赖声明的文档

TL;DR

  • 在所有 Lerna 管理的项目中:
    • 开发设施依赖(包括测试、构建等工具)都声明在项目根目录的 package.jsondevDependencies
  • 在由 create-next-repo 新建的仓库中:
    • 如果有某个包依赖了其它仓库(例如 brick-next)中的构件包、模板包,需要在仓库根目录中的 devDependencies 中额外声明它们。
  • @bricks/* 包中:
    • Custom Templates 依赖的其它构件包声明在 peerDependencies,版本号需要按 semver 正确声明;
    • @next-dll/* 的依赖声明在 peerDependencies,并且版本号只需要填写 *
    • 其它依赖声明在 devDependencies
  • @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 依赖了 BB 依赖了 C,那么在 A 包中执行 yarn 时,B C 都会被安装。
  • peerDependencies 不会被自动安装。
  • lerna version 发布版本时,会自动更新内部子包之间的 dependenciesdevDependencies 的版本。

结合上述内容和我们的需求,就不难理解我们如何管理 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 大仓库模式下这些包都在本地,所以不需要声明及安装。