前言
你是否曾经维护过多个前端项目?是否在多个项目之间来回复制粘贴组件,工具函数?是否经常被"组件更新没同步","构建时间太长","依赖版本冲突"等问题困扰?
这些问题都指向一个关键点: 项目结构和管理方式
今天,我来聊聊一种非常火但又容易被忽略的架构方式: Monorepo,并通过实例告诉它为什么在前端大型项目中越来越重要
一、背景与演进
1.1多仓(Multi-repo)时代的痛点
早期的前端项目采用(一个项目一个仓库)的方式(Multi-repo)管理:
-
组件复用困难:公共组件或工具库需要再npm发布后才能被其他项目引用,迭代慢,体验差
-
版本不一致,各项目间的依赖版本容易错乱,调试和排查成本高
-
CI/CD流程重复: 每个仓库都要单独配置流水线,维护成本高
-
分支管理复杂: 多个仓库多分支,跨仓库同步和合并麻烦
1.2 Monorepo的兴起
为了解决上述痛点,Google,Facebook,Twitter等大厂在内部率先实践了Monorepo(Monolithic Repository)----将多模块,多应用统一放在一个Git仓库中管理,随着社区工具的成熟,前端也迎来了Monorepo的浪潮
二 Monorepo的核心概念
Monorepo: 将多个相关或相关的项目(子包,组件库,服务端代码,前端应用等)放在同一个版本库中,通过工作区或仓库配置一并管理
主要特征:
1.单一的Git仓库: 所有代码,文档,配置文件都在一个仓库下;
2.多package: 通过子目录(通常是packges/或modules/)区分不同项目
3.统一依赖管理: 一个跟package.json+锁文件(pnpm-lock.yaml.yarn.lock),所有子包共用;
4.自动本地链接: 子包之间可以本地互相引用,无需发布到npm
三. Monorepo 带来的核心价值
依赖一致性 单一锁文件保证所有包使用相同版本,避免环境下跑,线上不跑
实时模拟共享, 修改组件库或工具库后,子项目可立刻引用最新代码,提升开发体验
统一 CI/CD 一套流水线即可跑所有测试,构建,发布,易于维护
按需构建 结合Turborepo等,可对改动包记性增量构建,节省资源
集中发布 Leran/Changesets可自动检测变更包并发布到npm
四. Monorepo简介及其与包管理工具(npm,yarn,pnpm)之间的联系
包管理工具是用来管理项目依赖,发布包,安装依赖的工具,它们都提供了对工作区(workspace)的支持,允许在单个代码库中管理多个项目或包,这种工作区支持在单个代码库中同时开发,测试和管理读个相关的项目,而无需使用多个独立的代码仓库
关系:
这些包管理工具与Monorepo的关系在于它们可以为monorepo提供依赖安装和依赖管理的支持,借助自身对workspace的支持,允许在monorepo中不同子项目之间共享依赖项,并提供一种管理这些共享依赖项的方式,这可以简化依赖项管理和构建过程,并提高开发效率
五. Monorepo生态
Monore只是一个管理概念,实际上它并不代表某项具体的技术,更不是所谓的框架,开发人员要根据不同场景,不同研发习惯,使用相应的技术手段或者工具,来达到或者完善它的整个流程,从而达到更好的开发和管理体验
目前前端领域的Monorepo生态有一个很显著的特点就是只有库,而没有大一统的框架或者完整的构建系统来支持,目前工具形态上像是传统的Cmake那样的辅助工具,而不是像Gradle(构建语言+生态链)或Cargo(包管理器自身集成)那样统一的方式,可能未来的趋势是像nx或者turborepo这样的库要往完整的框架发展,或者包管理器自身就逐步支持相应的功能,不需要过多的三方依赖,以下介绍一下生态中的核心技术:
包管理方案
-
npm
npm 在v7才支持了workspaces,属于终于能用上了但是并不好用的情况,重点是比较慢,通常无法兼容存量的monorepo应用,出来的时间太晚了,不能像yarn支持自定义nohoist以应对某些依赖被hoist到monorepo root导致的问题,也没有做到像pnpm 以link的方式共享依赖,能显著的减少磁盘占用,除了npm自带之外没有其他优点 -
Yarn
最早支持 workspaces 模式的包管理器,配合 lerna 占据了大部分 monorepo,在比较长的一段时间里是 monorepo 的事实标准,缺点是 yarn 的共享包才会提升到 root node_modules 下,其他非共享库都会每个地方留一份,占用空间比较多,还有提升到 root 这一行为也会带来兼容性问题(有些包的 require 方式比较 hack)
yarn berry(2 ~ 3)
比较新的点就是 pnp 模式,pnp 模式是为了解决 node_modules 臃肿、复杂度过高的问题而来的,但是比较激进,所以很难支持现有的项目。不过 yarn 3 基本上把各个包管理的功能都支持了(nodeLinker 配置),从功能上可以算是最多,比较复杂,概念好多。吸收了部分竞争对手的优点,并开辟了许多有趣的功能特性。
-
pnpm
全称是 “Performant NPM”,即高性能的 npm。
如它在官方文档介绍的所说:“Saving disk space and boosting installation speed”,Pnpm 是一个能够提高安装速度、节省磁盘空间的包管理工具,并天然支持 Monorepo 的解决方案。除此之外,它也解决了很多令人诟病的问题,其中,比较经典的就是 Phantom dependencies(幻影依赖)。
pnpm 的优势:
-
安装依赖速度快,软/硬链接结合
-
安装过的依赖缓存全局复用,缓存逻辑基于文件块,不同版本的依赖可以只缓存 diff
-
自身支持 workspaces 相关
六、主流 Monorepo 工具链
6.1 pnpm+Workspaces
- 安装速度快,磁盘占用少: 基于硬链接和全局缓存
- 配置简单: 只需根目录创建pnpm-workspace.yaml
# pnpm-workspace.yaml
packages:
- 'packages/*'
- 'libs/*'
6.2 Yarn Workspaces
与pnpm类似,需在根package.json中添加:
{
"private":true,
"workspaces":["packages/*","libs/*"]
}
常与Lerna配合,管理版本发布
6.3 Lerna
-
早期最流行的Monorepo管理工具
- 功能:管理多个包的版本,发布,依赖分析
- 可与npm,Yarn,pnpm结合使用
6.4 Turborepo
-
Vercel 出品,专注构建加速
-
增量构建、构建缓存、并行执行任务
-
支持多语言、多框架
7.总结
- Monorepo将多个子项目统一到一个仓库,实现依赖一致,模块共享,构建加速
- 工具选型: pnpm+Work 轻量高效; Turborepo构建优化; Lerna/Changesets自动发布
- 实践要点:明确模块边界,配置增量构建,自动化CI/CD,合理版本策略
如果你管理多个前端项目,组件库或者正在探索微前段和微服务,Monorepo将是你提升开发效率和团队协作的最佳实践!