banner
NEWS LETTER

单一仓库 Monorepo

Scroll down

Monorepo

Monorepo 是一个单一的存储库,包含多个不同的项目,和明确的关系。

能解决什么问题?

不仅仅在于减少了维护和管理多个代码库的成本,同时还有以下优点:

  • 代码复用:因为多个项目共享一个代码库,所以避免了在不同项目中重复编写相同功能代码的问题,提高了开发效率。
  • 提升协作效率:多个项目在同一个代码库中进行开发,可以方便地共享代码和文档,避免不同项目之间的沟通和协调成本。
  • 集中管理:Monorepo 架构中,不同的应用程序都在同一个代码库中,方便管理和监控。这一点非常重要,特别是在需要同时对多个版本进行修改和维护的情况下。
  • 统一构建:Monorepo 的一个重要特点是可以共用一套构建系统和工具链进行构建和部署,提升了构建的效率。
  • 可以快速定位问题:由于所有的代码都在同一个代码库中进行开发,debugger 可以很快找出问题所在的代码文件和行数,便于开发人员调试问题。
  • 一个版本:无需担心因为项目依赖于第三方库的冲突版本而导致的不兼容问题。

Monorepo 的基本组织方式如下

├── packages
| ├── pkg1
| | ├── package.json
| ├── pkg2
| | ├── package.json
├── package.json

packages 目录下存放多个子项目,当然也可以叫其他名字,每个子项目都有自己的 package.json 文件,用来管理子包。

几种组织方式

不搭配微前端

公共组件,库,api 跟项目分离,将项目放到 packages 目录中

├── components
├── api
├── utils
├── packages
| ├── pkg1
| | ├── package.json
| ├── pkg2
| | ├── package.json
├── package.json

请保证已安装 pnpm, 随后执行如下命令

pnpm init

项目根目录新建 pnpm-workspace.yaml 文件,注意要共享依赖的包,一定要在下面定义

packages:
- 'packages/*'
- 'components/**'
- 'api/**'

创建 packages 文件夹, 然后创建公共目录 比如 apicomponents等,跟 packages 文件夹同级

示栗:

mkdir api && cd api && pnpm init && pnpm add axios

api 根目录下,创建对应的文件,进行封装和引用以及导出

比如,axios.ts 封装 api 代码 user.ts 是具体使用, index.ts 导出,注意,这里 index 是因为当前包的 package.json 文件 main 主入口文件 main 指向的就是 index.ts 文件

然后,定义子包的名称,建议 @目录名/api,并且在 main 下面添加 private:true 代表私有的包

接着切换到对应的项目,在对应的项目使用公开的依赖包

pnpm add @cheny/api  注意,如果不行需要添加--workspace

搭配微前端

目录结构组织方式如下参考:

├── apps
| ├── 基础工程 - 比如 `微前端`
| | ├── package.json - 微前端的应用装在这里
| ├── 子应用二
| | ├── package.json
| ├── 子应用三
| | ├── package.json
├── packages
| ├── components
| | ├── package.json
| ├── utils
| | ├── package.json
├── package.json 公用依赖包 - 基础应用 - 河床

其他部分

项目只允许 pnpm 来开发,可以在 package.json 中的 script 指定

"preinstall": "npx only-allow pnpm"

设置 node 的基础版本

"engines": {"node":">=20"}

子包设置发布,在子包 package.json

"publishConfig": {"access":"public"}

包之间互相引用

pnpm -F @cheny/project1 add @cheny/test-api

给某个包安装依赖

pnpm add axios --filter @qftjs/monorepo1

怎么进行相应的发布呢?

登录 npm,npn login

Changesets

changesets 主要关心 monorepo 项目下子项目版本的更新、changelog 文件生成、包的发布。一个 changeset 是个包含了在某个分支或者 commit 上改动信息的 md 文件,它会包含这样一些信息:

  • 需要发布的包
  • 包版本的更新层级(遵循 semver 规范)
  • CHANGELOG 信息

changesets 的执行流程大概可以理解为:生成临时的 changelog → 消耗 changelog 生成组件的更新记录,并更新组件 version → 发布组件

monorepo

changesets 的工作流程是这样:开发者在 monorepo 项目下进行开发,开发完成后,给对应的子项目添加一个 changesets 文件。项目的维护者后面会通过 changesets 来消耗掉这些文件并自动修改掉对应包的版本以及生成 CHANGELOG 文件,最后将对应的包发布出去。

安装,通过 changsets 管理包版本,需要将它安装到最外层的包根目录包

pnpm install @changesets/cli -w --save-dev

初始化 changeset 在项目根目录下生成一个 .changeset 目录,里面会生成一个 changesetconfig 文件。linked 字段改成你自己的包名

pnpm changeset init

注意,👉 如果 config 中有个 access,如果后面 npm 发版时,npm 报错 unscoped 之类的,可以把这里修改为 public。默认是另外一个值,可以在官方 github 中查看。

预发布

pnpm changeset pre enter <tag>   alpha | beta | rc

退出预发布

pnpm changeset pre exit

正式发布

pnpm changest && pnpm changest version && pnpm changest publish

配置 changeset 发布流命令,在根目录的 package.json 添加以下命令:

"changeset": "changeset",
"update:version": "changeset version",
"release": "changeset publish",

其中: - changeset:生成临时的 changelog - update:version:消耗 changelog 生成组件的更新记录,并更新组件 version - release:发布组件

构建产物后发版本

{
"release": "pnpm build && pnpm release:only",
"release:only": "changeset publish --registry=https://registry.npmjs.com/"
}

栗子: // package.json 新增 如下配置


"scripts": {
// 构建整个项目的产物
"build": "pnpm -r --filter ./packages run build",
// 1. 开始交互式填写变更集
"changeset": "changeset",
// 2. 用来统一提升版本号
"vp": "changeset version",
// 3. 构建产物后发版
"release": "pnpm build && pnpm release:only",
"release:only": "changeset publish --registry=https://registry.npmjs.com/"
}

业务项目发布流是怎么样的?

  • 不同开发者先开发,在提交 PR 时使用 pnpm changeset 写入一份变更集。
  • 定期项目 owner 发包,使用 pnpm vp 消耗所有变更集,由 changesets 自动提升子包版本、生成 changelog
  • 执行 pnpm release 构建全部项目并发包。

monorepo

我很可爱,请给我钱

其他文章