技术探索Monorepo架构
BreezliMonorepo架构策略
更高效的代码共享和管理
为什么使用
项目不断膨胀 -> 构建速度↓↓↓ -> 包体积↑↑↑ -> 性能越来越慢
比如说想开发一个组件库,我在开发时需要启动 单组件测试、页面预览 两个服务,也就是需要在两个或多个项目中复用内部组件和逻辑,这时候我们就需要Monorepo架构来优化项目。
简要概述
项目结构 (以我的组件库项目为例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| root ├── node_modules/ ├── ...... │ ├── packages │ ├── components(组件实现) │ ├── node_modules/ │ ├── ...... │ └── package.json │ ├── docs(项目一:组件库页面) │ ├── node_modules/ │ ├── ...... │ └── package.json │ └── play(项目二:组件测试页面) │ ├── node_modules/ │ ├── ...... │ └── package.json │ ├── ...... ├── pnpm-workspace.yaml └── package.json //依赖会
|
这样我们可以同时启动多个项目,并能合并所有子项目共用的包到根目录下,在减少整体项目包体积的前提下,packages下的各项目能做到相互独立互不影响。
如何初始化
配置 pnpm-workspace.yaml
PNPM 工作区的配置文件,用于管理多个包之间的依赖关系
基础代码
1 2
| packages: - "packages/*"
|
所有位于 packages
目录下的子目录都被视为独立的包,并且是工作区的一部分
扩展
例如
1 2 3
| packages: - "packages/*" - "libs/*"
|
同样的,libs
目录下的子目录也被视为独立的包,被视为工作区的一部分
如果你有一个包在 packages
文件夹中依赖了另一个位于 libs
文件夹中的包,PNPM 不会从远程仓库下载该依赖,而是创建一个符号链接指向该本地包的位置。
当你在一个工作区内的任意一个包中安装依赖时,PNPM 会将这些依赖安装在工作区根目录下的 node_modules
文件夹内。工作区内所有的包可以共享相同的依赖版本,减少了重复安装和存储空间的浪费
配置 package.json
位于根目录,我的组件库项目叫tyche
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| { "name": "tyche", "version": "1.0.0", "main": "index.js", "scripts": { "dev": "pnpm --filter @tyche/play dev", "test": "pnpm --filter @tyche/components test" }, "packageManager": "pnpm@10.4.1", "devDependencies": { ...... }, "dependencies": { "@tyche/components": "workspace:*", "@tyche/hooks": "workspace:*", "@tyche/theme": "workspace:*", "@tyche/utils": "workspace:*", "tyche": "workspace:*", ...... } }
|
/// 补充:peerDependencies ///
1 2 3 4 5 6 7 8 9
| ├── helloWorld │ └── node_modules │ ├── packageA │ ├── plugin1 │ │ └── nodule_modules │ │ └── packageA │ └── plugin2 │ │ └── nodule_modules │ │ └── packageA
|
packageA 核心依赖库被重复下载
此时我们应该在
plugin1 /package.json
& plugin2 /package.json
1 2 3 4 5
| { "peerDependencies": { "packageA": "1.0.1" } }
|
/package.json
1 2 3 4 5
| { "dependencies": { "packageA": "1.0.1" } }
|
结构就变成了
1 2 3 4 5
| ├── helloWorld │ └── node_modules │ ├── packageA │ ├── plugin1 │ └── plugin2
|
通常用于库或插件,这些库或插件不直接包含在最终应用中,但需要与其他包协同工作
当你安装一个包时,如果该包有peerDependencies,npm或yarn会检查这些依赖是否已经安装在项目中,如果没有,它会给出警告,但不会默认安装它们