开篇:为什么我们要做 Monorepo
做企业级项目的同学大概率都遇到过这些痛点:
- 后台管理系统 + 可视化大屏拆分成两个仓库,公共工具、类型定义、请求封装来回复制粘贴,改一处要同步好几个项目;
- 两个项目依赖版本不统一,同一个
ElementPlus版本不一样,样式、API经常出现异常; - 本地开发要开两个终端、跑两次
dev命令,切换项目麻烦,构建配置重复维护; - 新手要拉好几个仓库,环境配置一套一套配,上手成本极高。
这就是典型的多仓(Multirepo)维护困境。而 pnpm + Monorepo 就是目前前端行业解决这类问题的最优解:一个仓库管理多个项目,共享依赖、共享公共代码、统一工程规范。
本系列我们就以「Vue3 人事管理后台 + 商用可视化大屏」双业务项目为载体,从零落地一套企业级可复用的 Monorepo 架构,全程贴合真实公司开发规范,学完可以直接套用到公司项目里。
本篇是系列第一篇,我们用 30 分钟搭好最核心的基础骨架,完成双项目迁入。
一、前置环境准备
| 工具 | 版本要求 | 说明 |
|---|---|---|
| Node.js | ≥ 18.x | 推荐 LTS 版本,Vite5、Vue3.5 都要求 Node18+ |
| pnpm | ≥ 8.x | 本系列全程使用 pnpm,性能和 workspace 支持都是最优 |
检查环境命令:
bash
node -v # 查看当前系统已安装的 node 版本
pnpm -v # 查看当前系统已安装的 pnpm 版本
如果没装 pnpm,执行全局安装:
bash
npm install -g pnpm
二、第一步:初始化 Monorepo 根项目
Monorepo 的核心是 「一个根仓库 + 多个子项目」,所有全局配置、依赖管理、脚本命令都统一在根目录。
- 新建项目根文件夹,命名为
hrms-monorepo,并进入目录:
bash
mkdir hrms-monorepo
cd hrms-monorepo
- 初始化根目录的
package.json:
bash
pnpm init
# 或执行兜底方式(任何版本都能用)
echo '{"name":"项目名称","version":"1.0.0","type":"module"}' > package.json
📢 注意:
pnpm v10 版本对
init命令做了参数重构,删除了 npm/yarn 那种init -y自动确认逻辑 ,不再支持-y/--yes参数实现自动确认初始化。
- 修改根目录
package.json,补充基础信息和关键配置:
json
{
"name": "hrms-monorepo",
"version": "1.0.0",
"description": "Vue3人事后台 + 商用大屏 Monorepo 企业级项目",
"private": true,
"type": "module",
"author": "咖啡无伴侣",
"license": "MIT"
}
关键说明:
private: true必须加,Monorepo 根项目是私有管理的,不会发布到 npm;type:module统一使用 ES Module 规范,和 Vite 项目保持一致。
三、第二步:配置 Workspace 工作区(核心)
pnpm Monorepo 靠 pnpm-workspace.yaml 来识别哪些目录是工作区子项目,这是整个框架的核心配置文件。
在根目录新建 pnpm-workspace.yaml:
yaml
# pnpm 工作区配置
packages:
# 业务项目:所有可独立运行的应用放这里
- 'apps/*'
# 公共包:所有可复用的公共模块放这里,后续逐步新增
- 'packages/*'
目录分层设计(企业级标准规范)
-
apps/: 存放独立运行的业务应用,每个都是完整可打包的项目
apps/hrms-admin:人事管理后台系统apps/hrms-screen:商用可视化大屏
-
packages/ 存放可复用的公共依赖包,给所有 apps 项目引用
- 后续逐步新增:
@hrms/shared公共工具、@hrms/types公共 TS 类型、@hrms/request统一请求封装、@hrms/components公共组件
- 后续逐步新增:
这种「业务层 + 公共层」的分层结构,即保证了业务项目的独立性,又实现了公共代码的统一复用。
四、第三步:新建两个业务子项目
把我们之前的两个 Vue 项目,创建在 apps 目录下。
- 根目录新建
apps文件夹:
bash
mkdir apps
- 创建两个项目,目录结构如下:
plaintext
hrms-monorepo/
├── apps/
│ ├── hrms-admin/ # 人事后台项目(完整的Vue3+Vite工程)
│ │ ├── src/
│ │ ├── package.json
│ │ └── vite.config.ts
│ └── hrms-screen/ # 可视化大屏项目(完整的Vue3+Vite工程)
│ ├── src/
│ ├── package.json
│ └── vite.config.ts
├── package.json
└── pnpm-workspace.yaml
📢 关键注意事项
-
子项目的
package.json里的name字段建议改成带作用域的格式,方便后续内部引用:- hrms-admin 的 name 改为
@hrms/admin - hrms-screen 的 name 改为
@hrms/screen
示例(apps/hrms-admin/package.json):
json{ "name":"@hrms/admin", "version":"1.0.0", "private":true, "type":"module", "scripts":{ "dev":"vite", "build":"vue-tsc && vite build", "preview":"vite preview" } // ... 其他依赖配置保留不变 } - hrms-admin 的 name 改为
-
删除两个子项目的
.vscode、README.md文件;两个子项目里如果有.npmrc、.gitignore可以删除了,后续统一在根目录管理,避免配置分散。
五、第四步:根目录统一工程化配置
Monorepo 的一大优势就是全局统一规范,所有配置只维护一份,所有子项目自动生效。
1. 根目录新建 .npmrc(统一包管理器规则)
和我们之前单项目的配置完全一致,全局生效,所有人、所有子项目依赖行为完全统一:
ini
# 国内镜像源
registry=https://registry.npmmirror.com
disturl=https://npmmirror.com/dist
sass_binary-site=https://npmmirror.com/mirrors/node-sass
electron_mirror=https://npmmirror.com/mirrors/electron
# 依赖版本严格锁定
save-exact=true
save-prefix=~
# 强制校验 Node 版本、包管理器
engine-strict=true
package-manager-strict=true
# 关闭无用提示
fund=false
audit=false
update-notifier=false
# pnpm 依赖提升兼容第三方库
public-hoist-pattern[]=*element-plus*
public-hoist-pattern[]=*vue*
public-hoist-pattern[]=*echarts*
2. 根目录新建 .gitignore(统一忽略文件)
所有子项目的 node_modules、dist、环境变量都统一在这里忽略:
plaintext
# 依赖目录
node_modules
.pnpm-store
# 打包产物
dist
dist-ssr
*.local
# 编辑器
.vscode/*
!.vscode/extensions.json
!.vscode/settings.json
.idea
# 系统文件
.DS_Store
Thumbs.db
# 日志
*.log
npm-debug.log*
pnpm-debug.log*
3. 根目录统一脚本命令
在根目录 package.json 里添加全局脚本,实现「一条命令管理所有项目」
json
{
"scripts":{
# 全局安装所有依赖
"install:all":"pnpm install",
# 分别启动项目
"dev:admin":"pnpm --filter @hrms/admin dev",
"dev:screen":"pnpm --filter @hrms/screen dev",
# 分别打包项目
"build:admin":"pnpm --filter @hrms/admin build",
"build:screen":"pnpm --filter @hrms/screen build",
# 一键打包所有项目
"build:all":"pnpm -r build"
}
}
核心知识点:
--filter是 pnpm 的筛选指令,指定只对某个工作区项目执行命令,是 Monorepo 多项目管理的核心语法。-r是递归执行所有子项目。
六、第五步:安装依赖 & 验证效果
所有配置完成后,在根目录执行一次安装命令:
bash
pnpm install
验证是否成功
-
看根目录是否只生成一份
node_modules,所有依赖都提升到根目录统一管理,子项目里不会再有冗余的node_modules; -
执行启动后台项目命令,看是否能正常运行:
bash
pnpm dev:admin
- 执行启动大屏项目命令,验证双项目都能正常启动:
bash
pnpm dev:screen
如果两个项目都能正常启动、正常访问,说明 Monorepo 基础骨架搭建完成。
本篇小结
本篇我们完成了 Nonorepo 最核心的基础搭建:
- ✅ 统一环境规范,确定 pnpm + Node18 + 的基础要求
- ✅ 配置 pnpm workspace,完成 「apps 业务层 + packages 公共层」的分层架构
- ✅ 完成人事后台、可视化大屏双项目迁入
- ✅ 根目录统一
.npmrc、.gitignore工程化配置 - ✅ 全局脚本统一管理,一条命令启动 / 打包任意项目
到这里,我们已经解决了「多项目依赖不统一、启动维护麻烦」的基础问题。但这只是开始,Monorepo 真正的价值 ------------公共代码复用、统一类型定义、跨项目共享组件,我们会在后面的篇章逐步落地。
【避坑指南】pnpm install 报错 ERR_PNPM_UNSUPPORTED_ENGINE 版本不兼容
触发场景
Monorepo 根目录首次执行 pnpm install 安装依赖时触发,使用 Vite 新版官方模板创建的子项目大概率会遇到。
完整报错信息
plaintext
Scope: all 3 workspace projects
/Users/xxx/Documents/hrms-monorepo/apps/hrms-admin: ERR_PNPM_UNSUPPORTED_ENGINE Unsupported environment (bad pnpm and/or Node.js version)
This error happened while installing a direct dependency of /Users/xxx/Documents/hrms-monorepo/apps/hrms-admin
Your Node version is incompatible with "npm-run-all2@9.0.2".
Expected version: ^22.22.2 || ^24.15.0 || >=26.0.0
Got: v20.20.0
This is happening because the package's manifest has an engines.node field specified. To fix this issue, install the required Node version.
Progress: resolved 1, reused 0, downloaded 0, added 0
报错原因
- 我们在
.npmrc中开启了engine-strict=true严格引擎校验,pnpm 会检查所有依赖包的 Node 版本要求,不匹配直接中断安装,而非仅输出警告。 - 新版 Vite 官方默认依赖的
npm-run-all@9.x抬高了 Node 版本门槛,要求 Node ≥22.22.2,和当前企业主流的 Node 18/20 LTS 版本不兼容。
两种解决方案
方案一:关闭严格校验(个人学习/Demo 项目首选)
最简单快速的处理方式,版本不匹配仅警告不中断安装,完全不影响正常开发使用。
修改根目录.npmrc:
ini
# 将 true 改为 false
engine-strict=false
修改完成后重新执行 pnpm install 即可。
方案二:锁定依赖版本(企业级项目推荐,保留严格规范)
通过 pnpm 的 overrides 能力,强制全仓库使用兼容 Node 20 的低版本依赖,保留工程化严格校验规则。
在根目录 package.json 中新增配置:
json
{
"pnpm":{
"overrides":{
"npm-run-all2":"^8.0.0"
}
}
}
修改完成后重新执行 pnpm install 即可。
💡 面试高配考点
第一篇(Monorepo 基础搭建)
- 说一下 Monorepo 和多仓模式的区别,各自有什么优缺点?
- pnpm workspace 是怎么管理依赖的,和 lerna 相比优势在哪?
- 你们公司为什么要做 Monorepo 改造,解决了什么实际问题?
下一篇预告
第02篇:公共包初体验 ------ 抽取统一 TS 类型定义包,实现双项目共享,告别重复写 interface。