pnpm monorepo 实践

509 阅读4分钟

背景

作者近段时间主要都是在维护不同的小程序H5项目,这些项目都是单独分不同仓库,甚至有些简单的H5页面是用原生写的。在我们内部又没有一些UI规范和开发规范,就导致了大多数情况下的开发效率极其低 (即使很多情况下设计稿长得都大差不差)

那么在不同的小程序和H5中总是可以抽离一些通用的UIutils,但是目前的情况下又没办法直接做到无缝使用,既没有相应的文档记录也没有比较好的抽离使用,每次新开发都可能会经历同样的内容出现在不同的工程目录下 (复制粘贴)

于是就想到了在未来是否可以使用monorepo的方式来统一管理这类应用,简单地了解了一下不同工具管理monorepo的方案后最终选择直接采用 pnpm workspace 来进行管理

项目主要目录结构

graph TD
A(项目根目录) --> B(common);
A --> C(miniprogram); 
A --> D(web); 
B --> E(components); 
B --> F(utils); 
C --> H(小程序项目1)
C --> I(小程序项目2)
C --> J(小程序项目3)
D --> K(H5项目1)
D --> L(H5项目2)
D --> M(H5项目3)

在这个统一管理的项目背景下,我们的components组件和utils工具函数都不需要单独发包管理,利用workspace的方式即可做到引入使用,使用到的内容故会随着项目工程打包内置其中

遇到的问题

  1. 如何集成单体Multirepo的已有CI至该monorepo工程下
  2. 如何在该仓库中管理不同项目或公共内容的研发全流程规范

针对于第一点的背景: 我们目前已有的项目都是集成该私有化部署CI工具 drone 来实现我们的自动化构建流程

  • 对于小程序项目我们有专门的一个OSS镜像服务来上传编译后的产物至OSS上,用于小程序自动化构建平台
  • 对于web项目我们是使用docker打包构建后产物镜像至独立的项目阿里云镜像仓库

在这之前我们的生产环境CI流程都是利用DRONE_TAG来触发的,即git tag v${major}.${minor}.${patch}, 既方便版本号管理也方便 CD 时的镜像切换

但是该方案不能沿用于monorepo架构下的项目管理方案

  1. 不同项目的版本迭代周期不一致,故统一的git tag版本号规范不能同时使用于不同的业务项目
  2. 不同项目如何管理其对应的 dev、test、prerelease、prod 环境的代码并触达相应的 CI

经讨论后,我们期望的是在dev、test等非稳定版本内容分支下,通过不同的业务项目路径是否存在内容修改来触发对应的流水线 CI,例如在gitlab中的 only changes,大意是在符合某个glob匹配的路径下有内容变化时,则触发当前 job

但是针对于要上线 prod 的生产稳定版本内容时的管理,我们期望的是不同项目能够有单独的version管理,又不希望破坏以往存在的规范,则有了以下的几个尝试性方案

方案一

弃用之前的drone plugin方案 drone docker plugin,用于打包部署镜像到远程镜像仓库

自行编写相关打包脚本并统一管理不同项目的version,开始踩坑后发现在独立的Docker环境中运行Docker相关指令有些奇怪并没有找到存在docker的镜像 (后面又仔细找了一下drone相关的文章似乎是有的)

方案二

流水线中传递version,同gitlab ci在不同 jobs中传递变量的方案 (能用但有点蠢),但是好像在不同的进程中共享变量的方式也只有这样了?

方案三

tips: 这也是我回去又重新看了一遍 Drone 文档考虑过后觉得可用的方案

image.png

利用其本身的能力写入 .tag 文件中即可触发同等 version配置能力

image.png

大概原理是拿到 ${DRONE_TAG}内容后做字符串替换的能力即可,那么我们就有了以下方案

以往的trigger规则: git tag v${major}.${minor}.${patch},修改为git tag${project_name}@v ${major}.${minor}.${patch}

再利用Drone提供的相关能力,编写不同项目的yml内容即可实现不同的CI

最终采用的方案

在以上几个方案中的调研与实践中,作者最终选择了 方案三 中打不同 tag 的方案

再回到上面提到的 问题2,其实团队中完整的研发流程离不开每一位小伙伴开发习惯和共同规范后的努力,不同的开发背景下总会存在的一定的问题

针对与该仓库的研发规范我总结为以下的流程 (在只有一个测试环境的背景下)

  1. master 切出 feature/projectName_featureName 或 feature/projectName_version
  2. 假如有并行开发时自行维护单次使用的共同分支 (feature/projectName_common)
  3. 提测前检查是否代码合并完成(并解决完冲突)后合入 test 分支交付于测试
  4. 测试过程中有内容修改则回到自己的 feature 分支修改完成后重复上述步骤
  5. 测试通过后将本次的 feature 分支合并至 prerelease 分支 (避免 test 环境中存在别的开发者在本次迭代中未完成测试的产物)
  6. 产品验收过程中出现问题则重复上述研发流程步骤,无问题则验收完毕后 prerelease 分支合并至 master 分支,并打对应的 tag 完成本次版本迭代

不同的团队、不同的背景下总会存在不同的规范,上述规范可能也只是我们目前跑下来相对较好的方案了,大佬们轻喷

Future

目前该方案也只是使用在新项目开启的时候采用,以往的已有项目就不做相关迁移了 (考虑成本的问题) , 也已经有新项目在落地使用了

一些公共的轮子还需要团队中各个成员的贡献,工程上也存在一些 To DoTo Refactor 的能力需要补充

  • 提供统一脚本管理不同项目的开发等等(pnpm run dev、 pnpm run build)等能力等统一集成
  • 关于公共能力的单测、回归等还需慢慢集成
  • 文档能力的补齐

小小的吐槽

网上搜了一圈聊 Drone 的文档实在是太少啦,小团队估计还处于 纯手动Jenkins 的历史包袱下,大团队不是 自建体系就是 gitlab ci,在了解了该工具之后感觉还是蛮香的哈哈,希望日后社区内有更多介绍 Drone 的文章