介绍
Monorepo,即单个代码库,是一种软件开发模式,在一个仓库中维护多个项目并共享公共代码。它的出现可以提高项目的开发效率和代码复用性,同时避免了多个代码仓库之间的协同问题,因此越来越受到开发者们的青睐。本文将介绍 Monorepo 的应用场景,以及如何使用 pnpm workspace 搭建 Monorepo 代码仓库。前言铺垫这么多,就举个例子介绍下 monorepo 的应用场景,比如现在有个 UI 组件库的开源项目。
应用场景
作为一种软件开发模式,Monorepo 的应用场景比较广泛,这里举一个例子。
假设有一个 UI 组件库的开源项目,除了需要有组件库的代码,还可能需要包括脚手架、工具库、插件等内容,并且这些内容都要作为 npm 包发布。如果使用传统的开发方式,每个项目都要作为单独的 npm 项目来发布引用,就需要创建多个代码仓库,即“多代码库(multirepos)”。这样在开发和代码仓库的协同上肯定存在弊端,而 Monorepo 则将所有项目放在一个代码仓库中,即“单一代码库(monorepos)”,解决了协同问题。
这只是 monorepo 的一个应用场景例子,这里有一个更好的例子 前端工程化:如何使用 monorepo 进行多项目的高效管理,更多可以参考使用 monorepo 的开源项目来了解。在 这里 可查看使用了 pnpm 工作空间功能的最受欢迎的开源项目。
有篇文章推荐阅读 5 分钟搞懂 Monorepo - 简书 (jianshu.com)
这里还有份手册可供阅读 What is a Monorepo? | Turborepo
项目结构
pnpm 内置了对单一存储库(也称为多包存储库、多项目存储库或单体存储库)的支持, 你可以创建一个 workspace 以将多个项目合并到一个仓库中。
pnpm 要使用 monorepo 的话,需要创建 pnpm-workspace.yaml 文件,其内容如下
packages:
- 'packages/*'
其中 packages 为多项目的存放路径(一般为公共代码),pnpm 将 packages 下的子目录都视为一个项目。此外如果项目还有文档或在线演示的项目(这些不作为核心库),放在 packages 有些许不妥,就可以像下面这样来配置 workspace
packages:
- packages/*
- docs
- play
像一开始所举例的代码仓库的项目结构如下
monorepo-demo
├── package.json
├── packages
│ ├── components # 组件库
│ │ ├── index.js
│ │ └── package.json
│ ├── cli # CLI
│ │ ├── index.js
│ │ └── package.json
│ ├── plugins # 插件
│ │ ├── index.js
│ │ └── package.json
│ ├── utils # 工具
│ │ ├── index.js
│ │ └── package.json
├── docs # 文档
│ │ ├── index.js
│ │ └── package.json
├── play # 在线演示
│ │ ├── index.js
│ │ └── package.json
├── pnpm-lock.yaml
└── pnpm-workspace.yaml
其中 packages 下存放的就是多个项目代码库,假设项目就叫 demo(因为到时候这些包是有可能要发布的,而名字就要保证唯一),那么项目的 package.json 如下演示:
{
"name": "@demo/components",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"type": "module",
"license": "ISC",
"dependencies": {
"@packages/utils": "workspace:^1.0.0"
}
}
安装依赖
执行pnpm install
会自动安装所有依赖(包括 packages 下)
假设现在我要为某个项目添加依赖,例如为 utils 模块添加 lodash 的话,pnpm 提供 --filter
选项来指定包安装依赖,命令如下
pnpm --filter <package_selector> <command>
例如:
pnpm -F @demo/utils add lodash
-F
等价于--filter
假设现在写好了 utils 模块,@demo/components
准备使用 utils 模块,可以按照如下操作
pnpm -F @demo/components add @demo/utils@*
这个命令表示在@demo/components
安装@demo/utils
,其中的@*
表示默认同步最新版本,省去每次都要同步最新版本的问题。
启动项目
使用node packages/component (默认执行 index.js 文件)
node packages/components
更好的选择是编写 npm scripts 就像下面这样:
"scripts": {
"test": "vitest",
"dev": "pnpm -C play dev",
"docs:dev": "pnpm run -C docs dev",
"docs:build": "pnpm run -C docs build",
"docs:serve": "pnpm run -C docs serve",
},
其中-C path 表示 在 path 下运行 npm 脚本 而不是在当前工作路径下。例如根目录下执行 npm run docs:dev
便会执行 docs/package.json
dev
脚本,同理build
和serve
也是一样。
此外更多的可能会在根目录下创建 script 脚本,然后编写(编译,发布)脚本。
Turborepo
在上面只是介绍了使用 pnpm workspace 来搭建一个 monorepo 的仓库,但很多时候还需要搭配适当的工具来扩展 monorepo, Turborepo 就是其中之一,利用先进的构建技术和思想来加速开发,构建了无需配置复杂的工作。
这里就不做介绍,这篇 🚀Turborepo:发布当月就激增 3.8k Star,这款超神的新兴 Monorepo 方案,你不打算尝试下吗? - 掘金 (juejin.cn) 就非常值得推荐阅读。
总结
搭建 Monorepo 仓库虽然简单,但并不是所有项目都适合使用 Monorepo。由于多项目共用一个代码仓库,启动速度可能会比单项目启动更慢,因此应该根据实际情况选择是否使用 Monorepo。Monorepo 的出现可以提高项目的开发效率和代码复用性,同时避免了多个代码仓库之间的协同问题,因此在适当的情况下使用 Monorepo 是有很多优势的。
相关文章
5 分钟搞懂 Monorepo - 简书 (jianshu.com)
前端工程化:如何使用 monorepo 进行多项目的高效管理
🚀Turborepo:发布当月就激增 3.8k Star,这款超神的新兴 Monorepo 方案,你不打算尝试下吗? - 掘金 (juejin.cn)