Monorepo 是管理项目代码的一个方式,指在一个项目仓库 (repo) 中管理多个模块/包 (package),不同于常见的每个模块建一个 repo。
目前有不少大型开源项目采用了这种方式,如 Babel:
How is the repo structured?
The Babel repo is managed as a monorepo that is composed of many npm packages.
还有 create-react-app, react-router 等。可以看到这些项目的第一级目录的内容以脚手架为主,主要内容都在 packages
目录中、分多个 package 进行管理。
├── packages | ├── pkg1 | | ├── package.json | ├── pkg2 | | ├── package.json ├── package.json
monorepo 最主要的好处是统一的工作流和Code Sharing。比如我想看一个 pacakge 的代码、了解某段逻辑,不需要找它的 repo,直接就在当前 repo;当某个需求要修改多个 pacakge 时,不需要分别到各自的 repo 进行修改、测试、发版或者 npm link
,直接在当前 repo 修改,统一测试、统一发版。只要搭建一套脚手架,就能管理(构建、测试、发布)多个 package。
不好的方面则主要是 repo 的体积较大。特别是,因为各个 package 理论上都是独立的,所以每个 package 都维护着自己的 dependencies,而很大的可能性,package 之间有不少相同的依赖,而这就可能使install
时出现重复安装,使本来就很大的 node_modues
继续膨胀(我称这为「依赖爆炸」...)。
基于对以上的理解,我认为当项目到一定的复杂度,需要且可以划分模块、但模块间联系紧密的,比较适合用 monorepo 组织代码。
目前最常见的 monorepo 解决方案是 Lerna 和 yarn
的 workspaces
特性。其中,lerna 是一个独立的包,其官网的介绍是:
a tool that optimizes the workflow around managing multi-package repositories with git and npm.
上面提到的 Babel, create-react-app 等都是用 lerna 进行管理的。在项目 repo 中以lerna.json
声明 packages 后,lerna 为项目提供了统一的 repo 依赖安装 (lerna bootstrap
),统一的执行 package scripts (lerna run
),统一的 npm 发版 (lerna publish
) 等特性。对于「依赖爆炸」的问题,lerna 在安装依赖时提供了--hoist
选项,相同的依赖,会「提升」到 repo 根目录下安装,但……太鸡肋了,lerna 直接以字符串对比 dependency 的版本号,完全相同才提升,semver 约定在这并不起作用。
具体的使用方法移步 Lerna 官网:https://lerna.js.org
而使用 yarn 作为包管理器的同学,可以在 package.json
中以 workspaces
字段声明 packages,yarn 就会以 monorepo 的方式管理 packages。相比 lerna,yarn 突出的是对依赖的管理,包括 packages 的相互依赖、packages 对第三方的依赖,yarn 会以 semver 约定来分析 dependencies 的版本,安装依赖时更快、占用体积更小;但欠缺了「统一工作流」方面的实现。
yarn 官网对 workspace
的详细说明:Workspaces | Yarn
lerna 和 yarn-workspace 并不是只能选其一,大多 monorepo 即会使用 lerna 又会在 package.json
声明 workspaces
。这样的话,无论你的包管理器是 npm 还是 yarn,都能发挥 monorepo 的优势;要是包管理是 yarn ,lerna 就会把依赖安装交给 yarn 处理。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗