本文主要是介绍Monorepo设计思路(Speeches),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
先言
This article is a speech
结构设计
位置 | 作用 |
---|---|
libs/* | 提供基础能力、框架、sdk、组件库等 |
apps/* | 业务应用(微前端子应用、整体应用) 核心,所有基础能力为业务服务 |
templates/* | 各种模板 |
utils/* | 赋能工具 |
.../* | 更多分类… |
驱动模式
基础能力 - libs
领域范围
- sdk:埋点 / 环境变量 / 请求方法 / 高层封装工具等等…
- 组件库:表单 / 联动组件 / 复杂组件等等…
- 框架:业务自洽性,必要的黑盒、限制,缺省配置,收敛等…
- 等等…
技术范围
- tsc 、rollup、webpack 等打包工具
- 框架(swc 、esbuild、mfsu 等)
- 组件库的依赖
- 等等…
如何丝滑
支持 monorepo 引用热更新
monorepo redirect 思路定位到 src
源码支持热更新
解耦、可复用
- 多抽离,多分层
- 明确上下级链路调用、依赖关系
- 长远发展视角设计,向前兼容
解多重依赖
有几种定位依赖的策略、做法:
事项 | 解法 |
---|---|
重要依赖唯一定位 | 框架帮助重定位重要 dep 位置,保持唯一性。 如 react / react-dom / react-router / react-router-dom / antd 等 alias 唯一定位,防多 hooks 问题 |
peerDeps 定位 | 因为依赖会先用他文件夹内的 devDeps ,违背了 npm 依赖的思维。 需不需要定位依赖的 peerDeps 解掉这个问题? |
dependenciesMeta 定位 | 重定位还是 dependenciesMeta 模拟真实 npm 包的行为?建议重定位 |
其他符合场景的定位 | 还需要定位哪些? 根据场景来 |
核心业务 - apps
全部场景覆盖。
领域范围
-
微前端设计
i. 基座
ii. 子应用:一个 平台 / 页面 作为子应用,能随处找坑插入,独立部署,独立工作流
-
不光是微前端
i. 搭配 nginx / 网关 / cdn / nodejs 等实现非微前端应用的项目
技术范围
- qiankun
- react 、react-dom 等业务依赖
- 自由发挥、限制…
如何丝滑
减少不必要的代码
- 减少微前端初始化 runtime 、入口配置代码。如 umi 中间层
- 减少配置。默认好用,缺省最优,收敛、抽象配置方法到 lib 里。
- 减少依赖。如抽取组件来解,umi all in one 的思路等
初始化容易
- 让新项目 create 的轻且易,生成文件思路不限,如 cli 从云拉取 template 的最新版本 npm 依赖,再做必要的替换。
- 考虑 微前端、非微前端、组件库 等等多场景更好
其他支持 - templates / utils / …
领域范围
用 workspace dir 来分类的原则,存放你需要分类的事物。
如:
- eslint-config / plugin
- template
- 适应你场景需要的提效工具…
好处
在一套协作、发布流里,互相引用方便,可以同时更新发布,版本一致性等
坏处
东西多了造成冗余
顶层 - root
领域范围
分类 | 解法 |
---|---|
全局脚本 | 发布脚本、规范化脚本、依赖操作脚本等 |
全局配置 | 1. eslint / prettier / editorconfig 等是否需要一统? 一统后子项目无需再配,不一统自由度更高,可设计继承 2. tsconfig.base.json 等可最大程度复用的配置,多写点继承,少 copy 3. changesets / turbo 等等… |
技术范围
- changesets 发布流
- turborepo / pnpm filter 构建流
- zx 等常用支持工具
如何丝滑
配置收敛多少
根据场景来,比如有组件库的 tsconfig.base
,有业务项目用的 tsconfig.app
,多玩继承。
必要的全局依赖
评估好哪些需要提升到全局,好处是只升级一处就可以,否则要跑到无数子项目 package.json
里去打苦工。
比如从以下视角出发价值判断:
- 开发依赖:
rimraf
、zx
、chalk
等开发用依赖提升风险小,收益高 - 组件库等:
antd
、icons
库、业务依赖 等业务生产依赖提升需思考,但业务项目可以自己再装自己的,需斟酌。 - 核心依赖:
react
、react-dom
等,是否需要提升?根据情况来 - 应用经验:
lodash
等库,常年不变动,放心提升
选择总 lock 还是分 lock
pnpm lock file 可以在全局,也可以在单独项目中。
位置 | 好处 | 坏处 |
---|---|---|
全局 lock | 最大程度复用,节省空间,安装速度快,一次即可搞定 all 项目 | 安装了一些不必要的依赖,每次提交影响全局 lock 文件起冲突 (好在 pnpm 处理 lock 文件的能力很强大,可以不提交 lock 找机会集中去 update) |
分项目 lock | 互相改动依赖不影响其他人,不会起冲突 | 依赖复用性差,每个项目都要执行 install script hook ,core-js 、swc 等大量库都有这个环节,速度奇慢无比 (pnpm 有选项来缓存 script 的结果,但第一次是否忍) |
在本文的设计场景中,因存在先置依赖,需要直接用产物,所以只能取全局 lock ,在 install 结束后,要预构建出必要的支持产物,再启动 app 中的 project。
构建流
每个 app 的 package.json#name
都遵守统一的格式,如:@scope/project-${app-id}
。
在构建时根据 id 注入环境变量,执行 turbo 最优顺序构建时,按照 name
格式拼接起来作为 --scope
值即可定点完成任务。
注:如果是自动 trigger 类的 cicd ,可以通过 webhook 等 api 识别 merge 进来的文件在哪个 path 下解,比如可以把 app id 也作为文件夹名,看看 change 到了哪个文件夹就知道哪个 app 要 build 了。
发布流
注意 changesets 还是会给 private: true
的子包( 比如 app 业务项目要限制 )生成 CHANGELOG
文件的,只有加入到 changeset 配置文件的 ignore
列表里才不会有这个冗余情况。
这里可以在发布的先置阶段,用 workspace 工具扫描然后自动填到 ignore
列表里来解。
设计思考
结构合理、庞大性
trade off。
把框架放在仓库是否冗余了,去掉?
- 好:运行 app 不用先构建出来框架的产物了
- 坏:不能即时得到最新变动 、fix 的收益
把全部 libs 分到其他 monorepo 仓库?
- 好:纯业务仓库,领域清真
- 坏:要从 npm 下载,没有
workspace:*
的即时引用,即时修改的敏捷开发好处了,当然分离多少是个 trade off。
仓库庞大性
trade off。
支持派
- 都放在一起,业务领域一览无疑,不用到处跳 repo,交接、新人学习成本低,互相复用真爽
- 即时改动,即时热更新,可以享受到最新的变动
depth=1
,删除分支,静态资源提前上云 等减小仓库体积- facebook 等厂均是单仓主干开发
反对派
- 冗余成本
- 随着发展仓库体积增大,拉取速度慢
- 业务领域不清晰,混杂不清真
资源分享
pnpm
-
为什么使用pnpm可以光速建立好用的monorepo(比yarn/lerna效率高)
-
pnpm monorepo之多组件实例和peerDependencies困境回溯
-
pnpm monorepo的技术选型临界点(Critical adoption)
changesets
-
monorepo工作流基础之changesets打开与进阶(Speeches)
-
vary (自动扫描将 private: true 的包名添加到 changeset 配置文件 ignore 中的工具)
turborepo
-
使用Turborepo进行复杂拓扑关系的monorepo最优构建
-
Turborepo的进阶构建技巧和是与非
以上。
这篇关于Monorepo设计思路(Speeches)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!