什么是Monorepo?
Monorepo 将许多不同项目集中在一个代码仓库中进行管理,这些项目在某种程度上相互依赖,但在逻辑上是独立的,这意味着不同的团队可以独立地进行工作。 与之相对的是 Multirepo,每个项目都拥有单独的代码仓库。
Monorepo 的优点:
- 代码共享和复用:在单一代码库中,不同项目和模块可以轻松地共享和复用代码,降低了重复开发的成本。
- 依赖管理:Monorepo 可以使开发人员更容易地管理项目间的依赖关系,减少了版本冲突和升级问题。
- 原子提交:Monorepo 允许开发人员在一个提交中更新多个项目或模块,这有助于保持代码的一致性。
- 更简洁的工作流程:使用 Monorepo 可以简化构建、测试和部署等工作流程,提高开发效率。
Monorepo 的缺点:
- 代码库规模:随着项目和代码的增长,Monorepo 的规模可能变得庞大,从而影响性能和存储需求。
- 权限管理:在一个大型代码库中管理访问权限可能变得复杂,特别是在多团队协作的情况下。
- 潜在的耦合:由于代码位于同一仓库中,可能导致不同项目之间的耦合过于紧密,影响项目的独立性和灵活性。
一些知名的开源项目,如 Next.js、Vite 和Element Plus,都采用了 Monorepo 策略。在选择 Monorepo 之前,需要权衡其优缺点,并考虑它是否适用于特定的开发环境和需求。
monorepo 方案实践
monorepo可以使用 lerna,也可以使用更简洁的 yarn、pnpm,但是 pnpm 相对于 yarn 包管理机制更加强大完善,所以我们采用 pnpm 实现 monorepo。
创建项目
首先,全局安装pnpm,创建项目目录,然后使用 pnpm init命令创建一个新的空项目。
sh代码解读复制代码npm i -g pnpm mkdir xxxx-monorepo cd ./xxxx-monorepo pnpm init
创建 pnpm Workspaces
根目录下必须有 pnpm-workspace.yaml 文件,它定义了工作空间的根目录
yaml代码解读复制代码packages: - packages/*
创建业务项目
使用 pnpm create vite命令在 packages 目录下创建project1项目
sh代码解读复制代码mkdir packages cd packages pnpm create vite project1 --template react cd project1 pnpm install pnpm dev
创建使用公共 utils
在 packages 目录下创建公共 utils 目录
sh代码解读复制代码mkdir utils
添加 package.json 文件
json代码解读复制代码{ "name": "@xxxx/utils", "main": "index.js", "version": "0.0.1" }
创建 log.js 文件
js代码解读复制代码const log = (text) => { console.log(text); }; export default log;
创建 index.js 入口文件,并导出 log 方法
js代码解读复制代码import log from ''./log.js''; export { log };
进入 packages/project1,添加 @xxxx/utils 依赖
sh代码解读复制代码cd ../packages/project1 pnpm add @xxxx/utils
在 App.jsx 中引用 log 方法
js代码解读复制代码import { log } from ''@xxxx/utils''; function App() { return ( <div className="App"> <button onClick={() => { log(''onClick''); }} ></button> </div> ); } export default App;
创建使用公共组件
在 packages 目录下创建 components 目录
sh代码解读复制代码mkdir packages/components cd packages/components
添加 package.json 文件
json代码解读复制代码{ "name": "@xxxx/components", "main": "index.js", "version": "0.0.1" }
创建 Button 组件
css代码解读复制代码packages/ ├── components/ │ └── Button/ │ └───index.tsx ├── utils/ └── project1/
在 index.tsx 文件中编写 Button 组件的代码。
jsx代码解读复制代码export default function Button(props) { return <button style={{ background: ''red'' }} {...props} />; }
创建 index.js 入口文件,并导出 Button 组件
js代码解读复制代码import Button from ''./Button''; export { Button };
进入 packages/project1,添加 @xxxx/components 依赖
sh代码解读复制代码cd ../packages/project1 pnpm add @xxxx/components
在 App.jsx 中引用 Button 组件
js代码解读复制代码import { log } from ''@xxxx/utils'' import { Button } from ''@xxxx/components''; function App() { return ( <div className="App"> <Button onClick={() => { log(''onClick''); }} ></Button> </div> ); } export default App;