基于 乾坤(qiankun) 的微前端 RBAC 权限管理后台。采用 pnpm Monorepo 管理主应用、子应用及公共包,支持本地开发、Docker 多环境部署。
| 类别 | 技术 |
|---|---|
| 框架 | Vue 3 + TypeScript 5 + Vite 6 |
| 微前端 | qiankun 2.x + vite-plugin-qiankun |
| 状态管理 | Pinia |
| 路由 | Vue Router 4(主应用动态路由 + RBAC) |
| UI | Element Plus 2.x |
| 样式 | UnoCSS |
| 包管理 | pnpm workspace |
| 部署 | Docker + Nginx |
graph TB
subgraph Browser["浏览器(同一 document)"]
Main["主应用 main-app :3000"]
Layout["Layout 壳层<br/>Sidebar + Header"]
Container["#micro-app-container"]
Main --> Layout
Layout --> Container
Container --> AppOne["子应用 app-one"]
Container --> AppTwo["子应用 app-two"]
end
subgraph Packages["公共包"]
Shared["@micro-app/shared<br/>类型 / 常量 / 工具"]
API["@micro-app/api<br/>Mock 接口服务"]
end
Main --> Shared
Main --> API
AppOne --> Shared
AppOne --> API
AppTwo --> Shared
AppTwo --> API
| 应用 | 包名 | 端口 | 路由前缀 | 说明 |
|---|---|---|---|---|
| 主应用 | @micro-app/main-app |
3000 | / |
登录、Layout、RBAC 权限、乾坤注册与调度 |
| 子应用一 | @micro-app/app-one |
3001 | /app-one |
用户管理 |
| 子应用二 | @micro-app/app-two |
3002 | /app-two |
角色管理、权限管理 |
- 静态路由:
/login、/403 - 动态路由:登录后根据用户权限生成,404 路由在动态路由加载完成后注册
- Layout 结构:单一 Layout 包裹所有页面,避免切换子应用时壳层重复挂载
/ (Layout)
├── dashboard # 主应用 - 仪表盘
├── app-one/:pathMatch(.*)* # 子应用 - 用户管理
└── app-two/:pathMatch(.*)* # 子应用 - 角色 / 权限管理
权限数据定义在 packages/api/src/mock/data.ts,菜单权限通过 microApp 字段区分归属:
| microApp | 菜单示例 | 乾坤 activeRule |
|---|---|---|
main |
仪表盘 /dashboard |
— |
app-one |
用户列表 /app-one/user/list |
/app-one |
app-two |
角色列表 /app-two/role/list |
/app-two |
主应用在 apps/main-app/src/micro-app.ts 中注册子应用:
| 配置项 | app-one | app-two |
|---|---|---|
| name | app1 |
app2 |
| activeRule | /app-one |
/app-two |
| container | #micro-app-container |
#micro-app-container |
| 开发 entry | //localhost:3001/app1/ |
//localhost:3002/app2/ |
| 生产 entry | /app1/ |
/app2/ |
注意:子应用 entry 地址必须带尾部斜杠(如
/app1/),否则 Vite 开发服务器会返回 404。
micro-app/
├── apps/
│ ├── main-app/ # 主应用
│ │ ├── src/
│ │ │ ├── layout/ # 布局壳层(Sidebar / Header / 微应用容器)
│ │ │ ├── pages/ # 登录、仪表盘、错误页
│ │ │ ├── router/ # 路由守卫 + 动态路由
│ │ │ ├── store/ # Pinia 认证状态
│ │ │ ├── utils/permission.ts # 权限 → 路由转换
│ │ │ └── micro-app.ts # 乾坤注册
│ │ ├── .env.development
│ │ ├── .env.production
│ │ ├── Dockerfile
│ │ └── nginx.conf # 生产环境代理子应用
│ ├── app-one/ # 子应用 - 用户管理
│ └── app-two/ # 子应用 - 角色 / 权限管理
├── packages/
│ ├── shared/ # 公共类型、常量、工具函数
│ └── api/ # Mock API 服务(auth / user / role / permission)
├── docker-compose.local.yml # 本地 Docker(端口 3000/3001/3002)
├── docker-compose.test.yml # 测试环境(主应用 8030)
├── docker-compose.prod.yml # 生产环境(主应用 80)
├── pnpm-workspace.yaml
└── package.json
- Node.js >= 18
- pnpm >= 9
# 启用 pnpm(如未安装)
corepack enable
corepack prepare pnpm@latest --activatepnpm install推荐:同时启动三个应用
pnpm dev| 应用 | 地址 |
|---|---|
| 主应用 | http://localhost:3000 |
| 子应用 app-one | http://localhost:3001/app1/ |
| 子应用 app-two | http://localhost:3002/app2/ |
也可单独启动:
pnpm dev:main # 仅主应用
pnpm dev:app-one # 仅子应用一
pnpm dev:app-two # 仅子应用二密码均为 123456:
| 用户名 | 角色 | 权限范围 |
|---|---|---|
admin |
超级管理员 | 全部菜单与按钮 |
editor |
运营编辑 | 仪表盘 + 用户管理 |
viewer |
访客 | 只读(仪表盘、用户/角色/权限列表) |
| 变量 | 开发环境 | 生产环境 | 说明 |
|---|---|---|---|
VITE_BASE_URL |
/ |
/ |
主应用部署基础路径 |
VITE_APP_ONE_ENTRY |
//localhost:3001/app1/ |
/app1/ |
子应用一乾坤 entry |
VITE_APP_TWO_ENTRY |
//localhost:3002/app2/ |
/app2/ |
子应用二乾坤 entry |
| 变量 | 值 | 说明 |
|---|---|---|
VITE_BASE_URL |
/app1/ 或 /app2/ |
子应用部署基础路径,需与 Nginx / Vite 一致 |
# 构建全部应用
pnpm build
# 单独构建
pnpm build:main
pnpm build:app-one
pnpm build:app-two
# 类型检查
pnpm typecheck构建产物位于各应用 dist/ 目录。
三个服务均暴露端口,便于独立调试:
pnpm docker:local
# 或
docker compose -f docker-compose.local.yml up --build| 服务 | 端口 |
|---|---|
| main-app | 3000 |
| app-one | 3001 |
| app-two | 3002 |
主应用对外暴露 8030,子应用仅内网互通:
pnpm docker:test主应用对外 80 端口,子应用通过 Nginx 反向代理同域加载:
pnpm docker:prod主应用 nginx.conf 将子应用请求代理到 Docker 内网服务:
用户浏览器
→ main-app:80/
→ main-app:80/app1/ → proxy_pass app-one:80/
→ main-app:80/app2/ → proxy_pass app-two:80/
乾坤通过同域路径 /app1/、/app2/ 加载子应用,避免跨域问题。
本项目在微前端场景下做了以下样式隔离处理,后期开发请务必遵守:
Logo、Header、Sidebar 等壳层组件使用 scoped CSS,不依赖 UnoCSS 工具类,防止被子应用全局样式覆盖。
主应用 uno.config.ts 扫描三个应用的源码,只由主应用注入一份 virtual:uno.css。
子应用在乾坤模式下不再加载 UnoCSS / Element Plus CSS,复用主应用已注入的样式。
- 子应用根节点使用
.sub-app-root,避免与主应用#appID 冲突 - 乾坤容器为
#micro-app-container
// apps/main-app/src/micro-app.ts
start({
prefetch: false,
sandbox: { experimentalStyleIsolation: true },
})- 在
packages/api/src/mock/data.ts添加权限菜单(设置microApp字段) - 在
apps/main-app/src/utils/permission.ts的microAppConfigs注册路由前缀 - 在
apps/main-app/src/micro-app.ts注册乾坤子应用 - 在
apps/main-app/uno.config.ts的content.filesystem加入新子应用扫描路径 - 子应用路由
base在乾坤模式下设为对应的activeRule(参考 app-one) - 子应用
main.ts乾坤模式不重复加载全局 CSS
types/— User、Role、Permission、AppRoute 等类型定义constants/— Token、Storage Key 等常量utils/— 权限判断、树形构建、日期格式化等工具
基于 Mock 数据的接口服务,无真实后端:
authService— 登录 / 登出 / 获取权限userService— 用户 CRUDroleService— 角色 CRUDpermissionService— 权限 CRUD
后期接入真实 API 时,只需修改 packages/api/src/services/ 下的实现。
| 命令 | 说明 |
|---|---|
pnpm dev |
并行启动全部应用(开发) |
pnpm build |
构建全部应用 |
pnpm typecheck |
全项目 TypeScript 检查 |
pnpm docker:local |
Docker 本地环境 |
pnpm docker:test |
Docker 测试环境 |
pnpm docker:prod |
Docker 生产环境(后台运行) |
动态路由尚未加载时,404 兜底路由不能放在静态路由中。当前实现为:登录后动态注册业务路由,最后注册 404 路由。
检查主应用 .env 中 VITE_APP_*_ENTRY 是否带尾部斜杠,正确值为 /app1/ 而非 /app1。
原因:子应用重复注入全局 CSS(UnoCSS / Element Plus)覆盖主应用样式。
解决:确保子应用乾坤模式不加载全局 CSS;Layout 壳层使用 scoped CSS;主应用统一生成 UnoCSS。
Private