generator-mico-cli 0.2.1 → 0.2.2-8.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +199 -15
- package/bin/mico.js +232 -27
- package/generators/micro-react/index.js +200 -18
- package/generators/micro-react/meta.json +13 -0
- package/generators/micro-react/templates/.commitlintrc.js +1 -0
- package/generators/micro-react/templates/.cursor/rules/always-read-docs.mdc +14 -4
- package/generators/micro-react/templates/.cursor/rules/cicd-deploy.mdc +10 -8
- package/generators/micro-react/templates/.cursor/rules/coding-conventions.mdc +1 -1
- package/generators/micro-react/templates/.cursor/rules/development-guide.mdc +3 -4
- package/generators/micro-react/templates/.cursor/rules/layout-app.mdc +38 -31
- package/generators/micro-react/templates/.cursor/rules/project-overview.mdc +7 -4
- package/generators/micro-react/templates/.cursor/rules/theme-system.mdc +10 -12
- package/generators/micro-react/templates/.eslintrc.js +25 -1
- package/generators/micro-react/templates/AGENTS.md +5 -2
- package/generators/micro-react/templates/CICD/before_build.sh +76 -0
- package/generators/micro-react/templates/CICD/start_dev.sh +27 -3
- package/generators/micro-react/templates/CICD/start_prod.sh +26 -3
- package/generators/micro-react/templates/CICD/start_test.sh +28 -3
- package/generators/micro-react/templates/CICD/wangsu_fresh_dev.sh +4 -4
- package/generators/micro-react/templates/CICD/wangsu_fresh_prod.sh +4 -4
- package/generators/micro-react/templates/CICD/wangsu_fresh_test.sh +4 -4
- package/generators/micro-react/templates/CLAUDE.md +16 -9
- package/generators/micro-react/templates/README.md +42 -4
- package/generators/micro-react/templates/_gitignore +4 -0
- package/generators/micro-react/templates/_npmrc +4 -0
- package/generators/micro-react/templates/apps/layout/config/config.dev.ts +32 -16
- package/generators/micro-react/templates/apps/layout/config/config.prod.development.ts +24 -29
- package/generators/micro-react/templates/apps/layout/config/config.prod.testing.ts +25 -6
- package/generators/micro-react/templates/apps/layout/config/config.prod.ts +16 -7
- package/generators/micro-react/templates/apps/layout/config/config.ts +27 -4
- package/generators/micro-react/templates/apps/layout/config/routes.ts +5 -5
- package/generators/micro-react/templates/apps/layout/docs/arch-/346/227/245/345/277/227/344/270/216/345/270/270/351/207/217.md +2 -2
- package/generators/micro-react/templates/apps/layout/docs/common-intl.md +372 -0
- package/generators/micro-react/templates/apps/layout/docs/feat-/346/236/204/345/273/272define/344/270/216/345/205/215/350/256/244/350/257/201/345/210/235/345/247/213/346/200/201.md +44 -0
- package/generators/micro-react/templates/apps/layout/docs/feature-404/351/241/265/351/235/242.md +103 -0
- package/generators/micro-react/templates/apps/layout/docs/feature-/344/270/273/351/242/230/350/211/262/345/210/207/346/215/242.md +22 -26
- package/generators/micro-react/templates/apps/layout/docs/feature-/345/276/256/345/211/215/347/253/257/346/250/241/345/274/217.md +185 -28
- package/generators/micro-react/templates/apps/layout/docs/feature-/350/217/234/345/215/225/346/235/203/351/231/220/346/216/247/345/210/266.md +308 -63
- package/generators/micro-react/templates/apps/layout/docs/feature-/350/267/257/347/224/261/344/270/216/350/217/234/345/215/225/350/247/243/350/200/246.md +179 -0
- package/generators/micro-react/templates/apps/layout/docs/fix-SSO/346/227/240/351/231/220/351/207/215/345/256/232/345/220/221.md +88 -0
- package/generators/micro-react/templates/apps/layout/docs/utils-timezone.md +324 -0
- package/generators/micro-react/templates/apps/layout/mock/api.mock.ts +81 -61
- package/generators/micro-react/templates/apps/layout/mock/menus.ts +114 -4
- package/generators/micro-react/templates/apps/layout/mock/pages.ts +86 -0
- package/generators/micro-react/templates/apps/layout/package.json +7 -4
- package/generators/micro-react/templates/apps/layout/src/app.tsx +111 -76
- package/generators/micro-react/templates/apps/layout/src/common/auth/index.ts +3 -0
- package/generators/micro-react/templates/apps/layout/src/common/helpers.ts +177 -0
- package/generators/micro-react/templates/apps/layout/src/common/locale.ts +22 -17
- package/generators/micro-react/templates/apps/layout/src/common/menu/parser.ts +192 -42
- package/generators/micro-react/templates/apps/layout/src/common/menu/types.ts +69 -5
- package/generators/micro-react/templates/apps/layout/src/common/micro/index.ts +34 -0
- package/generators/micro-react/templates/apps/layout/src/common/micro-prefetch.ts +109 -0
- package/generators/micro-react/templates/apps/layout/src/common/portal-data.ts +45 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/config.ts +72 -10
- package/generators/micro-react/templates/apps/layout/src/common/request/index.ts +2 -2
- package/generators/micro-react/templates/apps/layout/src/common/request/interceptors.ts +31 -3
- package/generators/micro-react/templates/apps/layout/src/common/request/sso.ts +29 -11
- package/generators/micro-react/templates/apps/layout/src/common/request/url-resolver.ts +1 -1
- package/generators/micro-react/templates/apps/layout/src/common/route-guard.ts +345 -0
- package/generators/micro-react/templates/apps/layout/src/common/theme.ts +2 -4
- package/generators/micro-react/templates/apps/layout/src/common/upload/oss.ts +3 -4
- package/generators/micro-react/templates/apps/layout/src/common/upload/types.ts +1 -1
- package/generators/micro-react/templates/apps/layout/src/common/uploadFiles.ts +1 -1
- package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.less +8 -3
- package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.tsx +25 -8
- package/generators/micro-react/templates/apps/layout/src/components/HeaderDropdown/index.tsx +20 -0
- package/generators/micro-react/templates/apps/layout/src/components/IconFont/index.tsx +5 -6
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.less +21 -6
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +83 -149
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/micro-app-manager.ts +569 -0
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/AvatarDropdown.tsx +383 -0
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/avatar-dropdown.less +35 -0
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/index.ts +2 -0
- package/generators/micro-react/templates/apps/layout/src/constants/index.ts +170 -6
- package/generators/micro-react/templates/apps/layout/src/global.less +18 -9
- package/generators/micro-react/templates/apps/layout/src/hooks/useMenu.ts +3 -2
- package/generators/micro-react/templates/apps/layout/src/hooks/useRoutePermissionRefresh.ts +72 -0
- package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.less +3 -1
- package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.tsx +10 -55
- package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +34 -4
- package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +24 -8
- package/generators/micro-react/templates/apps/layout/src/layouts/index.less +84 -13
- package/generators/micro-react/templates/apps/layout/src/layouts/index.tsx +156 -69
- package/generators/micro-react/templates/apps/layout/src/locales/en-US.ts +12 -0
- package/generators/micro-react/templates/apps/layout/src/locales/zh-CN.ts +12 -0
- package/generators/micro-react/templates/apps/layout/src/pages/403/index.tsx +8 -2
- package/generators/micro-react/templates/apps/layout/src/pages/404/index.tsx +78 -0
- package/generators/micro-react/templates/apps/layout/src/pages/Home/index.less +3 -0
- package/generators/micro-react/templates/apps/layout/src/pages/Home/index.tsx +7 -1
- package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.less +1 -1
- package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.tsx +3 -3
- package/generators/micro-react/templates/apps/layout/src/requestErrorConfig.ts +1 -1
- package/generators/micro-react/templates/apps/layout/src/services/config/index.ts +63 -0
- package/generators/micro-react/templates/apps/layout/src/services/config/type.ts +30 -0
- package/generators/micro-react/templates/apps/layout/src/services/user.ts +29 -2
- package/generators/micro-react/templates/apps/layout/tailwind.config.js +3 -0
- package/generators/micro-react/templates/deployDesc.md +3 -3
- package/generators/micro-react/templates/dev.preset.json +14 -0
- package/generators/micro-react/templates/docs/dev-preset.md +130 -0
- package/generators/micro-react/templates/package.json +21 -6
- package/generators/micro-react/templates/packages/common-intl/README.md +427 -0
- package/generators/micro-react/templates/packages/common-intl/package.json +34 -0
- package/generators/micro-react/templates/packages/common-intl/src/index.ts +7 -0
- package/generators/micro-react/templates/packages/common-intl/src/indexedDBUtils.ts +51 -0
- package/generators/micro-react/templates/packages/common-intl/src/intl.ts +50 -0
- package/generators/micro-react/templates/packages/common-intl/src/utils.ts +482 -0
- package/generators/micro-react/templates/packages/common-intl/tsconfig.json +22 -0
- package/generators/micro-react/templates/packages/common-intl/vite.config.ts +25 -0
- package/generators/micro-react/templates/scripts/apply-sentry-plugin.ts +45 -0
- package/generators/micro-react/templates/scripts/collect-dist.js +10 -0
- package/generators/micro-react/templates/scripts/dev-preset.js +265 -0
- package/generators/micro-react/templates/scripts/dev-preset.schema.json +39 -0
- package/generators/micro-react/templates/turbo.json +4 -1
- package/generators/subapp-react/index.js +326 -40
- package/generators/subapp-react/meta.json +10 -0
- package/generators/subapp-react/templates/homepage/.env +2 -1
- package/generators/subapp-react/templates/homepage/README.md +3 -3
- package/generators/subapp-react/templates/homepage/config/config.dev.ts +14 -7
- package/generators/subapp-react/templates/homepage/config/config.prod.development.ts +16 -5
- package/generators/subapp-react/templates/homepage/config/config.prod.testing.ts +16 -5
- package/generators/subapp-react/templates/homepage/config/config.prod.ts +14 -5
- package/generators/subapp-react/templates/homepage/config/config.ts +21 -0
- package/generators/subapp-react/templates/homepage/config/routes.ts +2 -2
- package/generators/subapp-react/templates/homepage/mock/api.mock.ts +2 -2
- package/generators/subapp-react/templates/homepage/package.json +7 -4
- package/generators/subapp-react/templates/homepage/src/app.tsx +18 -27
- package/generators/subapp-react/templates/homepage/src/common/request.ts +29 -2
- package/generators/subapp-react/templates/homepage/src/global.less +6 -5
- package/generators/subapp-react/templates/homepage/src/pages/index.less +3 -3
- package/generators/subapp-react/templates/homepage/src/pages/index.tsx +99 -60
- package/generators/subapp-react/templates/homepage/src/styles/theme.less +1 -1
- package/generators/subapp-umd/ignore-list.json +5 -0
- package/generators/subapp-umd/index.js +309 -0
- package/generators/subapp-umd/meta.json +11 -0
- package/generators/subapp-umd/templates/README.md +94 -0
- package/generators/subapp-umd/templates/package.json +35 -0
- package/generators/subapp-umd/templates/public/index.html +34 -0
- package/generators/subapp-umd/templates/src/App.less +15 -0
- package/generators/subapp-umd/templates/src/App.tsx +13 -0
- package/generators/subapp-umd/templates/src/index.ts +2 -0
- package/generators/subapp-umd/templates/tsconfig.json +27 -0
- package/generators/subapp-umd/templates/webpack.config.js +70 -0
- package/lib/utils.js +332 -2
- package/package.json +15 -2
- package/generators/micro-react/templates/apps/layout/mock/menus.json +0 -100
- package/generators/micro-react/templates/apps/layout/src/common/constants.ts +0 -38
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/container-manager.ts +0 -202
- package/generators/micro-react/templates/packages/shared-styles/README.md +0 -124
- package/generators/micro-react/templates/packages/shared-styles/arco-design-mobile-override.less +0 -91
- package/generators/micro-react/templates/packages/shared-styles/arco-override.less +0 -119
- package/generators/micro-react/templates/packages/shared-styles/index.d.ts +0 -44
- package/generators/micro-react/templates/packages/shared-styles/index.less +0 -13
- package/generators/micro-react/templates/packages/shared-styles/package.json +0 -30
- package/generators/micro-react/templates/packages/shared-styles/theme-inject.less +0 -10
- package/generators/micro-react/templates/packages/shared-styles/themes/dark/custom-var.less +0 -290
- package/generators/micro-react/templates/packages/shared-styles/themes/normal/custom-var.less +0 -269
- package/generators/micro-react/templates/packages/shared-styles/variables-only.less +0 -433
- package/generators/micro-react/templates/packages/shared-styles/variables.less +0 -452
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# 构建 define 精简与免认证页初始态
|
|
2
|
+
|
|
3
|
+
> 创建时间:2026-03-24
|
|
4
|
+
|
|
5
|
+
## 功能概述
|
|
6
|
+
|
|
7
|
+
1. **Umi `define`**:不再通过构建期注入 `process.env.EXTERNAL_LOGIN_PATH`(本模板从未注入 `APP_ID`);SSO 外跳等依赖运行时 `window.__MICO_CONFIG__`。
|
|
8
|
+
2. **`getInitialState`**:免认证路由下即使本地仍有 token,也不请求用户信息接口,减少无效调用。
|
|
9
|
+
|
|
10
|
+
## 技术方案
|
|
11
|
+
|
|
12
|
+
### 开发环境
|
|
13
|
+
|
|
14
|
+
`config/config.dev.ts` 的 `headScripts` 中 `window.__MICO_CONFIG__` 增加 **`externalLoginPath`**(模板默认为占位 URL,生成项目后请按实际 IdP 修改)。
|
|
15
|
+
|
|
16
|
+
`define` 仅保留 `NODE_ENV`、`API_BASE_URL`、`LOGIN_ENDPOINT`、`REFRESH_ENDPOINT`。
|
|
17
|
+
|
|
18
|
+
### 生产 / 测试构建
|
|
19
|
+
|
|
20
|
+
`config.prod.ts`、`config.prod.development.ts`、`config.prod.testing.ts` 的 `define` 中同样**不包含** `EXTERNAL_LOGIN_PATH`,由部署时注入的 `__MICO_CONFIG__.externalLoginPath`(或 `__MICO_WORKSPACE__.casServerLoginUrl`)提供。
|
|
21
|
+
|
|
22
|
+
### 初始态
|
|
23
|
+
|
|
24
|
+
`src/app.tsx` 中仅在 `getStoredAuthToken() && !skipAuth` 时调用 `fetchUserInfoFn()`;`skipAuth = isNoAuthRoute || isPageAuthFree`。
|
|
25
|
+
|
|
26
|
+
## 文件清单
|
|
27
|
+
|
|
28
|
+
| 文件路径 | 说明 |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `config/config.dev.ts` | `__MICO_CONFIG__.externalLoginPath`;移除 `EXTERNAL_LOGIN_PATH` define |
|
|
31
|
+
| `config/config.prod.ts` | 移除 `EXTERNAL_LOGIN_PATH` define |
|
|
32
|
+
| `config/config.prod.development.ts` | 同上 |
|
|
33
|
+
| `config/config.prod.testing.ts` | 同上 |
|
|
34
|
+
| `src/app.tsx` | `fetchUserInfo` 条件增加 `!skipAuth` |
|
|
35
|
+
|
|
36
|
+
## 部署注意
|
|
37
|
+
|
|
38
|
+
- 生产 HTML 或网关需保证 `window.__MICO_CONFIG__` 含 **`appId`**、**`externalLoginPath`**(或与现有网关字段对齐),否则代理前缀、SSO 外跳可能异常。
|
|
39
|
+
- 详见 `src/common/request/config.ts` 中 `buildDefaultClientOptions` 的解析顺序。
|
|
40
|
+
|
|
41
|
+
## 相关文档
|
|
42
|
+
|
|
43
|
+
- [fix-SSO无限重定向](./fix-SSO无限重定向.md)
|
|
44
|
+
- [arch-请求模块](./arch-请求模块.md)
|
package/generators/micro-react/templates/apps/layout/docs/feature-404/351/241/265/351/235/242.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# 404 页面
|
|
2
|
+
|
|
3
|
+
> 创建时间:2025-01-27
|
|
4
|
+
|
|
5
|
+
## 功能概述
|
|
6
|
+
|
|
7
|
+
当用户访问不存在的路由时,展示 404 页面并提供导航选项,支持返回上页或跳转至第一个有权限访问的路由。
|
|
8
|
+
|
|
9
|
+
## 技术方案
|
|
10
|
+
|
|
11
|
+
### 技术栈
|
|
12
|
+
|
|
13
|
+
- 框架:React 18 + @umijs/max
|
|
14
|
+
- UI 组件:@mico-platform/ui `Result`、`Button`、`Space`
|
|
15
|
+
- 路由:React Router 6 通配符路由
|
|
16
|
+
|
|
17
|
+
### 核心实现
|
|
18
|
+
|
|
19
|
+
1. 使用 Umi 路由通配符 `/*` 捕获所有未匹配的路径
|
|
20
|
+
2. 复用 403 页面的布局风格,保持 UI 一致性
|
|
21
|
+
3. 动态计算第一个可访问路由:从菜单数据中提取路由,根据用户权限过滤后返回首个有效路径
|
|
22
|
+
|
|
23
|
+
## 文件清单
|
|
24
|
+
|
|
25
|
+
### 新增文件
|
|
26
|
+
|
|
27
|
+
| 文件路径 | 说明 |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `src/pages/404/index.tsx` | 404 页面组件 |
|
|
30
|
+
|
|
31
|
+
### 修改文件
|
|
32
|
+
|
|
33
|
+
| 文件路径 | 修改内容 |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `config/routes.ts` | 添加通配符路由 `/*` |
|
|
36
|
+
|
|
37
|
+
## API / 组件接口
|
|
38
|
+
|
|
39
|
+
### NotFoundPage
|
|
40
|
+
|
|
41
|
+
无外部 Props,使用 Umi 全局状态获取用户信息。
|
|
42
|
+
|
|
43
|
+
### getFirstAvailablePath
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
/**
|
|
47
|
+
* 获取第一个可访问的路由路径
|
|
48
|
+
*/
|
|
49
|
+
const getFirstAvailablePath = (filterOptions: MenuFilterOptions): string;
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**逻辑说明**:
|
|
53
|
+
|
|
54
|
+
1. 从 `window.__MICO_MENUS__` 获取菜单数据
|
|
55
|
+
2. 根据 `disableAuth` 配置决定是否过滤权限
|
|
56
|
+
3. 调用 `filterMenuItems` 过滤无权限菜单
|
|
57
|
+
4. 调用 `extractRoutes` 提取路由列表
|
|
58
|
+
5. 返回第一个路由的 `path`,若无则返回 `/`
|
|
59
|
+
|
|
60
|
+
## 路由配置
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// config/routes.ts
|
|
64
|
+
{
|
|
65
|
+
path: '/*',
|
|
66
|
+
component: './404',
|
|
67
|
+
name: '页面不存在',
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
通配符路由放在路由配置末尾,匹配所有未被其他路由匹配的路径。
|
|
72
|
+
|
|
73
|
+
## 使用示例
|
|
74
|
+
|
|
75
|
+
用户访问 `/non-existent-page` 时:
|
|
76
|
+
|
|
77
|
+
1. 路由系统无法匹配到具体路由
|
|
78
|
+
2. 通配符路由 `/*` 生效
|
|
79
|
+
3. 渲染 404 页面,显示两个按钮:
|
|
80
|
+
- **返回上页**:调用 `history.back()`
|
|
81
|
+
- **前往首页**:跳转至第一个有权限的路由
|
|
82
|
+
|
|
83
|
+
## 设计决策
|
|
84
|
+
|
|
85
|
+
| 决策点 | 选择 | 理由 |
|
|
86
|
+
| --- | --- | --- |
|
|
87
|
+
| UI 组件 | @mico-platform/ui Result | 与 403 页面保持一致,复用现有组件库 |
|
|
88
|
+
| 首页跳转逻辑 | 动态获取第一个可访问路由 | 适应动态菜单配置,不硬编码路径 |
|
|
89
|
+
| 权限过滤 | 复用 filterMenuItems | 与菜单权限逻辑保持一致 |
|
|
90
|
+
|
|
91
|
+
## 相关文件
|
|
92
|
+
|
|
93
|
+
| 文件 | 说明 |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| `src/pages/403/index.tsx` | 403 页面,UI 风格参考 |
|
|
96
|
+
| `src/common/menu/parser.ts` | 菜单解析工具函数 |
|
|
97
|
+
| `src/constants/index.ts` | `isAuthDisabled` 权限控制函数 |
|
|
98
|
+
|
|
99
|
+
## 注意事项
|
|
100
|
+
|
|
101
|
+
- 通配符路由必须放在路由配置最后,否则会提前匹配
|
|
102
|
+
- 动态路由(从 `window.__MICO_MENUS__` 注入)的 404 场景由 `layouts/index.tsx` 处理
|
|
103
|
+
- 此 404 页面主要处理静态路由未匹配的情况
|
|
@@ -11,7 +11,7 @@ Layout 应用支持亮色/暗黑主题切换,通过 CSS 变量实现运行时
|
|
|
11
11
|
### 技术栈
|
|
12
12
|
|
|
13
13
|
- 框架:React 18 + UmiJS 4
|
|
14
|
-
- UI
|
|
14
|
+
- UI 组件:@mico-platform/ui
|
|
15
15
|
- 样式:Less + CSS Variables
|
|
16
16
|
- 状态管理:React Hooks + localStorage
|
|
17
17
|
|
|
@@ -19,7 +19,7 @@ Layout 应用支持亮色/暗黑主题切换,通过 CSS 变量实现运行时
|
|
|
19
19
|
|
|
20
20
|
采用双属性主题系统:
|
|
21
21
|
|
|
22
|
-
1. `arco-theme` 属性控制
|
|
22
|
+
1. `arco-theme` 属性控制 @mico-platform/ui 组件主题(基于 Arco)
|
|
23
23
|
2. `data-theme` 属性控制自定义 CSS 变量
|
|
24
24
|
|
|
25
25
|
两个属性都设置在 `body` 元素上,确保选择器正确匹配。Less 变量引用 CSS 变量,实现编译时类型安全和运行时动态切换。
|
|
@@ -28,22 +28,19 @@ Layout 应用支持亮色/暗黑主题切换,通过 CSS 变量实现运行时
|
|
|
28
28
|
|
|
29
29
|
### 主题系统核心文件
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
主题变量由 `@mico-platform/theme` 包提供,主应用与子应用通过该包获取 CSS 变量与 Less 变量:
|
|
32
32
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
| `packages/shared-styles/variables.less` | Less 变量定义(引用 CSS 变量) |
|
|
39
|
-
| `packages/shared-styles/index.less` | 入口文件,导入全部(主应用用) |
|
|
40
|
-
| `packages/shared-styles/variables-only.less` | 仅 Less 变量(子应用用) |
|
|
33
|
+
| 入口/子路径 | 说明 |
|
|
34
|
+
| ------------------------------ | ------------------------------ |
|
|
35
|
+
| `@mico-platform/theme` | 主入口,CSS 变量 + Less 变量 |
|
|
36
|
+
| `@mico-platform/theme/variables` | 仅 Less 变量(子应用用) |
|
|
37
|
+
| `@mico-platform/theme/theme-inject` | 子应用独立运行时注入主题 |
|
|
41
38
|
|
|
42
39
|
### Layout 应用文件
|
|
43
40
|
|
|
44
41
|
| 文件路径 | 说明 |
|
|
45
42
|
| ---------------------------- | ----------------------------------------- |
|
|
46
|
-
| `src/global.less` | 导入
|
|
43
|
+
| `src/global.less` | 导入 `@mico-platform/theme` |
|
|
47
44
|
| `src/common/theme.ts` | 主题切换逻辑(`applyTheme`、`initTheme`) |
|
|
48
45
|
| `src/hooks/useTheme.ts` | 主题管理 Hook |
|
|
49
46
|
|
|
@@ -82,7 +79,7 @@ const { theme, isDark, toggleTheme, setTheme } = useTheme();
|
|
|
82
79
|
|
|
83
80
|
### 主要颜色变量
|
|
84
81
|
|
|
85
|
-
> 完整变量列表请参考
|
|
82
|
+
> 完整变量列表请参考 @mico-platform/theme 包文档
|
|
86
83
|
|
|
87
84
|
| 分类 | 变量 |
|
|
88
85
|
| ------ | --------------------------------------- |
|
|
@@ -129,7 +126,7 @@ const ThemeToggle: React.FC = () => {
|
|
|
129
126
|
### 常量定义
|
|
130
127
|
|
|
131
128
|
```typescript
|
|
132
|
-
// src/
|
|
129
|
+
// src/constants/index.ts
|
|
133
130
|
export const THEME = {
|
|
134
131
|
STORAGE_KEY: '<%= ProjectName %>-theme',
|
|
135
132
|
DEFAULT: 'light' as const,
|
|
@@ -151,8 +148,8 @@ export const THEME = {
|
|
|
151
148
|
|
|
152
149
|
```less
|
|
153
150
|
// apps/[子应用]/src/global.less
|
|
154
|
-
@import '
|
|
155
|
-
//
|
|
151
|
+
@import '@mico-platform/theme/variables';
|
|
152
|
+
// 主应用已注入 CSS 变量时,子应用仅需 Less 变量
|
|
156
153
|
```
|
|
157
154
|
|
|
158
155
|
#### 2. app.tsx - 开发环境条件注入
|
|
@@ -195,24 +192,24 @@ wc -c apps/[子应用]/dist/umi.css
|
|
|
195
192
|
# 期望:< 500 字节
|
|
196
193
|
```
|
|
197
194
|
|
|
198
|
-
###
|
|
195
|
+
### @mico-platform/ui 组件主题适配
|
|
199
196
|
|
|
200
|
-
子应用使用
|
|
197
|
+
子应用使用 @mico-platform/ui 组件时,组件样式会自动跟随主应用的主题切换。
|
|
201
198
|
|
|
202
199
|
#### 原理
|
|
203
200
|
|
|
204
|
-
1. 主应用加载
|
|
205
|
-
2.
|
|
201
|
+
1. 主应用加载 @mico-platform/ui 并暴露到 `window.micoUI`
|
|
202
|
+
2. 主应用的样式包含 `arco-theme` 属性选择器(基于 Arco)
|
|
206
203
|
3. 主应用切换主题时设置 `body[arco-theme="dark"]`
|
|
207
|
-
4. 子应用的
|
|
204
|
+
4. 子应用的 UI 组件(来自 window.micoUI)自动应用暗色样式
|
|
208
205
|
|
|
209
|
-
#### 子应用使用
|
|
206
|
+
#### 子应用使用 @mico-platform/ui
|
|
210
207
|
|
|
211
208
|
> 详细配置请参考 [微前端模式 - 依赖共享机制](./feature-微前端模式.md#依赖共享机制)
|
|
212
209
|
|
|
213
210
|
```tsx
|
|
214
|
-
// 子应用可以直接使用
|
|
215
|
-
import { Button, Card, Message, Tag } from '@
|
|
211
|
+
// 子应用可以直接使用 @mico-platform/ui 组件
|
|
212
|
+
import { Button, Card, Message, Tag } from '@mico-platform/ui';
|
|
216
213
|
|
|
217
214
|
export default function Page() {
|
|
218
215
|
return (
|
|
@@ -224,11 +221,10 @@ export default function Page() {
|
|
|
224
221
|
}
|
|
225
222
|
```
|
|
226
223
|
|
|
227
|
-
**注意**:子应用需要配置 `externals` 将
|
|
224
|
+
**注意**:子应用需要配置 `externals` 将 @mico-platform/ui 排除打包,详见 [微前端模式文档](./feature-微前端模式.md#依赖共享机制)。
|
|
228
225
|
|
|
229
226
|
## 相关文档
|
|
230
227
|
|
|
231
228
|
- [微前端模式](./feature-微前端模式.md) - qiankun 微前端架构与依赖共享
|
|
232
229
|
- [日志与常量](./arch-日志与常量.md) - Logger 工具与常量管理(含 THEME 常量)
|
|
233
|
-
- [shared-styles 包](../../../packages/shared-styles/README.md) - 共享样式包使用指南
|
|
234
230
|
- [提交规范](../../../docs/commit-message.md) - Git Commit 规范
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# 微前端模式
|
|
2
2
|
|
|
3
3
|
> 创建时间:2025-12-26
|
|
4
|
+
> 更新时间:2025-03-20(MicroAppLoader 增加 base 与 normalizeMicroAppBase)
|
|
4
5
|
|
|
5
6
|
## 功能概述
|
|
6
7
|
|
|
@@ -12,13 +13,13 @@
|
|
|
12
13
|
|
|
13
14
|
- 框架:React 18 + @umijs/max
|
|
14
15
|
- 微前端:qiankun (通过 @umijs/max 内置插件)
|
|
15
|
-
- UI
|
|
16
|
+
- UI 组件:@mico-platform/ui
|
|
16
17
|
- 路由:React Router 6
|
|
17
18
|
|
|
18
19
|
### 核心实现
|
|
19
20
|
|
|
20
|
-
1.
|
|
21
|
-
2.
|
|
21
|
+
1. 主应用优先通过 `window.__MICO_PAGES__` 获取页面配置,无数据时降级到 `window.__MICO_MENUS__`(详见 [路由与菜单解耦](./feature-路由与菜单解耦.md))
|
|
22
|
+
2. 解析页面时根据 `htmlUrl` 或 `jsUrls` 判断是否为微应用
|
|
22
23
|
3. 路由匹配时,微应用类型使用 `MicroAppLoader` 组件加载
|
|
23
24
|
4. `MicroAppLoader` 使用 qiankun 的 `loadMicroApp` API 动态挂载子应用
|
|
24
25
|
5. 组件卸载时自动调用 `unmount()` 清理子应用
|
|
@@ -27,14 +28,16 @@
|
|
|
27
28
|
|
|
28
29
|
### 核心文件
|
|
29
30
|
|
|
30
|
-
| 文件路径
|
|
31
|
-
|
|
|
32
|
-
| `src/components/MicroAppLoader/index.tsx`
|
|
33
|
-
| `src/components/MicroAppLoader/
|
|
34
|
-
| `src/
|
|
35
|
-
| `src/common/menu/
|
|
36
|
-
| `src/
|
|
37
|
-
| `
|
|
31
|
+
| 文件路径 | 说明 |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| `src/components/MicroAppLoader/index.tsx` | qiankun 微应用加载器组件 |
|
|
34
|
+
| `src/components/MicroAppLoader/micro-app-manager.ts` | 微应用管理器(单例),稳定容器 + 实例缓存 + 操作序列号 |
|
|
35
|
+
| `src/components/MicroAppLoader/index.less` | 加载器样式 |
|
|
36
|
+
| `src/common/menu/parser.ts` | 菜单解析,包含加载类型判断 |
|
|
37
|
+
| `src/common/menu/types.ts` | 类型定义 |
|
|
38
|
+
| `src/layouts/index.tsx` | 主布局,集成微应用渲染 |
|
|
39
|
+
| `src/app.tsx` | qiankun 全局错误处理 |
|
|
40
|
+
| `config/config.ts` | qiankun master 配置 |
|
|
38
41
|
|
|
39
42
|
## API / 组件接口
|
|
40
43
|
|
|
@@ -42,6 +45,8 @@
|
|
|
42
45
|
|
|
43
46
|
```typescript
|
|
44
47
|
interface MicroAppLoaderProps {
|
|
48
|
+
/** 微应用在主应用中的挂载路径前缀(来自 ParsedRoute.base / 页面配置 base),经 normalizeMicroAppBase 后传给子应用 */
|
|
49
|
+
base: string;
|
|
45
50
|
/** 微应用入口 URL */
|
|
46
51
|
entry: string;
|
|
47
52
|
/** 微应用名称 */
|
|
@@ -57,17 +62,53 @@ interface MicroAppLoaderProps {
|
|
|
57
62
|
|
|
58
63
|
| 参数 | 类型 | 必填 | 说明 |
|
|
59
64
|
|------|------|------|------|
|
|
65
|
+
| base | string | 是 | 挂载路径前缀;经 `normalizeMicroAppBase` 后作为子应用 `props.base` |
|
|
60
66
|
| entry | string | 是 | qiankun 入口 URL (htmlUrl 或 jsUrls[0]) |
|
|
61
67
|
| name | string | 是 | 微应用唯一标识 |
|
|
62
68
|
| displayName | string | 否 | 显示名称,用于加载提示 |
|
|
63
69
|
| routePath | string | 否 | 当前路由路径,用于子应用内部路由切换 |
|
|
64
70
|
|
|
71
|
+
### MicroAppLoader 路由与 base
|
|
72
|
+
|
|
73
|
+
主应用为微应用补充 **挂载前缀 `base`**,便于子应用对齐 basename、publicPath、内部路由等与路径相关的逻辑;**是否与免鉴权配置做前缀匹配**以当前实现为准(见下「加载门控」)。
|
|
74
|
+
|
|
75
|
+
#### `base` 与 `routePath` 的区别
|
|
76
|
+
|
|
77
|
+
| 字段 | 含义 |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| **base** | 该微应用在主应用中的**挂载前缀**,来自中台 **`page.base`**,解析为 **`ParsedRoute.base`**(缺省时解析为 **`'/'`**);可与动态路由 **`path`** 不同(如 `path` 为 `/subapp/*` 时 `base` 可为 `/subapp`)。 |
|
|
80
|
+
| **routePath** | 当前激活的**完整路由路径**,随浏览器 URL 变化,用于通知子应用做**内部路由同步**。 |
|
|
81
|
+
|
|
82
|
+
`routePath` 在布局内为 **`currentRoute.path`**。`base` 在 **`patchClientRoutes`** 与布局内均为 **`route.base` / `currentRoute.base`**。**`name`** 在布局侧常为基于 **`entry`** 的 **`getAppNameFromEntry`**,与 **`base`** 来源不同,需注意。
|
|
83
|
+
|
|
84
|
+
#### `normalizeMicroAppBase`
|
|
85
|
+
|
|
86
|
+
组件内导出工具函数(见 `MicroAppLoader/index.tsx`):
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
export const normalizeMicroAppBase = (path: string): string =>
|
|
90
|
+
path.replace(/\/+$/, '').replace(/\*+$/, '');
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
含义:先去掉末尾 `/`,再去掉末尾 `*`(兼容路由表中的 `/foo/*` 等写法)。**传给子应用的 `props.base` 为规范化后的字符串**。
|
|
94
|
+
|
|
95
|
+
#### 调用处传参
|
|
96
|
+
|
|
97
|
+
| 位置 | 说明 |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| `src/app.tsx` `patchClientRoutes` | 动态注册微应用路由时:`React.createElement(MicroAppLoader, { entry, name: route.path, base: route.base, ... })` |
|
|
100
|
+
| `src/layouts/index.tsx` | 布局内渲染:`<MicroAppLoader base={currentRoute.base} routePath={currentRoute.path} ... />` |
|
|
101
|
+
|
|
102
|
+
#### 加载门控(认证)
|
|
103
|
+
|
|
104
|
+
微应用开始执行 `switchTo` / 挂载前,需 **`isAuthReady`**(`isAuthDisabled`、`isPageAuthFree`、`isNoAuthRoute(location.pathname)`、`isNoPermissionRoute(location.pathname)` 或已存在 `currentUser` 等,见组件内实现)。**当前以浏览器 `location.pathname` 与全局常量为准**,未单独使用 `base` 与 `window.__MICO_CONFIG__.noAuthRouteList` 做前缀匹配。
|
|
105
|
+
|
|
65
106
|
### MicroAppProps (传递给子应用)
|
|
66
107
|
|
|
67
108
|
```typescript
|
|
68
109
|
interface MicroAppProps {
|
|
69
110
|
/** 主应用标识 */
|
|
70
|
-
mainApp: '
|
|
111
|
+
mainApp: '<%= projectName %>';
|
|
71
112
|
/** 运行环境 */
|
|
72
113
|
env: 'development' | 'testing' | 'production';
|
|
73
114
|
/** 认证 token */
|
|
@@ -84,6 +125,8 @@ interface MicroAppProps {
|
|
|
84
125
|
timezone: string;
|
|
85
126
|
/** 在线状态 */
|
|
86
127
|
presenceStatus: string;
|
|
128
|
+
/** 挂载路径前缀(为 `normalizeMicroAppBase(MicroAppLoader.base)`) */
|
|
129
|
+
base: string;
|
|
87
130
|
/** 当前路由路径 */
|
|
88
131
|
routePath?: string;
|
|
89
132
|
/** 共享的 request 实例,子应用可直接使用 */
|
|
@@ -122,6 +165,8 @@ export async function update(props: MicroAppProps) {
|
|
|
122
165
|
```typescript
|
|
123
166
|
interface ParsedRoute {
|
|
124
167
|
path: string;
|
|
168
|
+
/** 微应用挂载前缀(来自 page.base,解析缺省为 '/') */
|
|
169
|
+
base: string;
|
|
125
170
|
name: string;
|
|
126
171
|
icon: string;
|
|
127
172
|
/** 加载类型: internal(内部路由) | microapp(qiankun微应用) */
|
|
@@ -139,6 +184,8 @@ interface PageConfig {
|
|
|
139
184
|
id: number;
|
|
140
185
|
name: string;
|
|
141
186
|
route: string;
|
|
187
|
+
/** 微应用挂载前缀(可与 route 不同) */
|
|
188
|
+
base: string;
|
|
142
189
|
enabled: boolean;
|
|
143
190
|
/** 微应用 HTML 入口 URL (优先使用) */
|
|
144
191
|
htmlUrl: string | null;
|
|
@@ -208,7 +255,12 @@ const menus: MenuItem[] = [
|
|
|
208
255
|
const renderContent = () => {
|
|
209
256
|
if (currentRoute?.loadType === 'microapp' && currentRoute.entry) {
|
|
210
257
|
return (
|
|
211
|
-
<MicroAppLoader
|
|
258
|
+
<MicroAppLoader
|
|
259
|
+
entry={currentRoute.entry}
|
|
260
|
+
name={currentRoute.name}
|
|
261
|
+
base={currentRoute.base}
|
|
262
|
+
routePath={currentRoute.path}
|
|
263
|
+
/>
|
|
212
264
|
);
|
|
213
265
|
}
|
|
214
266
|
return <Outlet />;
|
|
@@ -253,9 +305,9 @@ export const getRequest = () => mainAppProps?.request;
|
|
|
253
305
|
|
|
254
306
|
### 问题背景
|
|
255
307
|
|
|
256
|
-
如果子应用直接安装 React
|
|
308
|
+
如果子应用直接安装 React、@mico-platform/ui 等大型库,会导致:
|
|
257
309
|
|
|
258
|
-
1. **包体积重复**:React (~140KB) +
|
|
310
|
+
1. **包体积重复**:React (~140KB) + UI 库 (~800KB) 被打包多次
|
|
259
311
|
2. **样式冲突**:多份 CSS 可能互相覆盖
|
|
260
312
|
3. **React 实例问题**:可能出现 "Invalid hook call" 错误
|
|
261
313
|
|
|
@@ -267,8 +319,8 @@ export const getRequest = () => mainAppProps?.request;
|
|
|
267
319
|
┌─────────────────────────────────────────────────────────────┐
|
|
268
320
|
│ 主应用 (layout) │
|
|
269
321
|
│ ┌─────────────────────────────────────────────────────────┐│
|
|
270
|
-
│ │ 1. 打包并加载 React、ReactDOM
|
|
271
|
-
│ │ 2. 暴露到 window.React / window.ReactDOM / window.
|
|
322
|
+
│ │ 1. 打包并加载 React、ReactDOM、@mico-platform/ui ││
|
|
323
|
+
│ │ 2. 暴露到 window.React / window.ReactDOM / window.micoUI ││
|
|
272
324
|
│ └─────────────────────────────────────────────────────────┘│
|
|
273
325
|
│ ↓ 共享 │
|
|
274
326
|
│ ┌─────────────────────────────────────────────────────────┐│
|
|
@@ -286,7 +338,7 @@ export const getRequest = () => mainAppProps?.request;
|
|
|
286
338
|
|
|
287
339
|
```typescript
|
|
288
340
|
// apps/layout/src/app.tsx
|
|
289
|
-
import * as
|
|
341
|
+
import * as micoUI from '@mico-platform/ui';
|
|
290
342
|
import React from 'react';
|
|
291
343
|
import ReactDOM from 'react-dom';
|
|
292
344
|
|
|
@@ -294,7 +346,7 @@ import ReactDOM from 'react-dom';
|
|
|
294
346
|
if (typeof window !== 'undefined') {
|
|
295
347
|
(window as any).React = React;
|
|
296
348
|
(window as any).ReactDOM = ReactDOM;
|
|
297
|
-
(window as any).
|
|
349
|
+
(window as any).micoUI = micoUI;
|
|
298
350
|
}
|
|
299
351
|
```
|
|
300
352
|
|
|
@@ -331,7 +383,7 @@ const config: ReturnType<typeof defineConfig> = {
|
|
|
331
383
|
externals: {
|
|
332
384
|
react: 'window.React',
|
|
333
385
|
'react-dom': 'window.ReactDOM',
|
|
334
|
-
'@
|
|
386
|
+
'@mico-platform/ui': 'window.micoUI',
|
|
335
387
|
},
|
|
336
388
|
};
|
|
337
389
|
|
|
@@ -359,23 +411,23 @@ export default defineConfig(config);
|
|
|
359
411
|
|
|
360
412
|
#### 3. package.json - 开发依赖
|
|
361
413
|
|
|
362
|
-
将
|
|
414
|
+
将 @mico-platform/ui 放在 `devDependencies`(用于类型提示和开发),生产环境从主应用获取。版本由生成器在创建子应用时从 npm 解析为当时最新版本(不使用 `latest` 标签):
|
|
363
415
|
|
|
364
416
|
```json
|
|
365
417
|
{
|
|
366
418
|
"devDependencies": {
|
|
367
|
-
"@
|
|
419
|
+
"@mico-platform/ui": "^x.x.x"
|
|
368
420
|
}
|
|
369
421
|
}
|
|
370
422
|
```
|
|
371
423
|
|
|
372
|
-
### 子应用使用
|
|
424
|
+
### 子应用使用 @mico-platform/ui
|
|
373
425
|
|
|
374
|
-
配置完成后,子应用可以正常导入和使用
|
|
426
|
+
配置完成后,子应用可以正常导入和使用 UI 组件:
|
|
375
427
|
|
|
376
428
|
```tsx
|
|
377
429
|
// apps/[子应用]/src/pages/index.tsx
|
|
378
|
-
import { Button, Card, Message, Tag } from '@
|
|
430
|
+
import { Button, Card, Message, Tag } from '@mico-platform/ui';
|
|
379
431
|
|
|
380
432
|
export default function HomePage() {
|
|
381
433
|
return (
|
|
@@ -393,7 +445,7 @@ export default function HomePage() {
|
|
|
393
445
|
|
|
394
446
|
| 配置方式 | 子应用 JS 体积 | 说明 |
|
|
395
447
|
| ------------------ | -------------- | ------------------------ |
|
|
396
|
-
| 直接安装依赖 | ~1.2MB | 包含 React +
|
|
448
|
+
| 直接安装依赖 | ~1.2MB | 包含 React + @mico-platform/ui |
|
|
397
449
|
| **externals 共享** | **~50KB** | 仅业务代码 |
|
|
398
450
|
|
|
399
451
|
### 运行环境说明
|
|
@@ -414,14 +466,15 @@ export default function HomePage() {
|
|
|
414
466
|
- 组件会在 `entry` 或 `name` 变化时重新加载微应用
|
|
415
467
|
- 加载失败会显示错误信息,便于调试
|
|
416
468
|
- **子应用应使用主应用传递的 `request` 实例**,确保认证 token 和拦截器一致
|
|
417
|
-
- **子应用使用 externals 共享依赖**,避免重复打包 React 和
|
|
469
|
+
- **子应用使用 externals 共享依赖**,避免重复打包 React 和 @mico-platform/ui
|
|
418
470
|
|
|
419
471
|
## 相关文档
|
|
420
472
|
|
|
473
|
+
- [路由与菜单解耦](./feature-路由与菜单解耦.md) - 路由注册与菜单导航数据源分离
|
|
474
|
+
- [菜单权限控制](./feature-菜单权限控制.md) - sideMenus 白名单权限逻辑
|
|
421
475
|
- [主题色切换](./feature-主题色切换.md) - 主题系统实现与子应用适配
|
|
422
476
|
- [请求模块架构](./arch-请求模块.md) - HTTP 请求层模块化设计
|
|
423
477
|
- [日志与常量](./arch-日志与常量.md) - Logger 工具与常量管理
|
|
424
|
-
- [shared-styles 包](../../../packages/shared-styles/README.md) - 共享样式包使用指南
|
|
425
478
|
- [提交规范](../../../docs/commit-message.md) - Git Commit 规范
|
|
426
479
|
|
|
427
480
|
## 加载类型判断逻辑
|
|
@@ -430,3 +483,107 @@ export default function HomePage() {
|
|
|
430
483
|
有 htmlUrl 或 jsUrls → microapp (使用 qiankun 加载)
|
|
431
484
|
无 htmlUrl 且无 jsUrls → internal (使用 Outlet 渲染)
|
|
432
485
|
```
|
|
486
|
+
|
|
487
|
+
## 加载健壮性机制
|
|
488
|
+
|
|
489
|
+
> 更新于 2025-01-25
|
|
490
|
+
|
|
491
|
+
### 解决的问题
|
|
492
|
+
|
|
493
|
+
| 原问题 | 风险 | 修复方案 |
|
|
494
|
+
|--------|------|----------|
|
|
495
|
+
| 无全局错误处理,子应用异常可能导致页面崩溃 | 高 | 添加 `addGlobalUncaughtErrorHandler` |
|
|
496
|
+
| unmount 使用 rAF 时序不可靠 | 高 | 使用 `queueMicrotask` |
|
|
497
|
+
| 同名应用并发加载可能冲突 | 高 | 会话 ID 锁 + `waitForUnmount` |
|
|
498
|
+
| unmount 可能永久卡死 | 中 | 10 秒超时机制 |
|
|
499
|
+
| 加载期间 Props 变化被跳过 | 中 | 加载完成后重新同步 Props |
|
|
500
|
+
|
|
501
|
+
### 全局错误处理
|
|
502
|
+
|
|
503
|
+
在 `src/app.tsx` 中注册 qiankun 全局错误处理器,捕获子应用运行时未捕获的异常:
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
import { addGlobalUncaughtErrorHandler } from 'qiankun';
|
|
507
|
+
|
|
508
|
+
addGlobalUncaughtErrorHandler((event: Event | string) => {
|
|
509
|
+
// 捕获子应用 JS 运行时错误
|
|
510
|
+
// 捕获子应用生命周期钩子异常
|
|
511
|
+
// 捕获资源加载失败
|
|
512
|
+
console.error('[qiankun] Global uncaught error:', event);
|
|
513
|
+
});
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### MicroAppManager API (micro-app-manager.ts)
|
|
517
|
+
|
|
518
|
+
`MicroAppManager` 是单例类,管理微应用的加载、缓存、切换和卸载:
|
|
519
|
+
|
|
520
|
+
```typescript
|
|
521
|
+
interface MicroAppConfig {
|
|
522
|
+
name: string;
|
|
523
|
+
entry: string;
|
|
524
|
+
target: HTMLElement; // 目标挂载位置
|
|
525
|
+
props: Record<string, unknown>;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
interface MicroAppState {
|
|
529
|
+
loading: boolean;
|
|
530
|
+
error: string | null;
|
|
531
|
+
mounted: boolean;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const manager = microAppManager; // 单例,导出即用
|
|
535
|
+
|
|
536
|
+
/** 切换到指定微应用(已挂载则仅更新 props) */
|
|
537
|
+
manager.switchTo(config: MicroAppConfig): void;
|
|
538
|
+
|
|
539
|
+
/** 更新当前已挂载微应用的 props */
|
|
540
|
+
manager.updateProps(props: Record<string, unknown>): void;
|
|
541
|
+
|
|
542
|
+
/** 取消待处理的请求 */
|
|
543
|
+
manager.cancel(): void;
|
|
544
|
+
|
|
545
|
+
/** 清除所有缓存实例 */
|
|
546
|
+
manager.clearCache(): Promise<void>;
|
|
547
|
+
|
|
548
|
+
/** 获取调试信息 */
|
|
549
|
+
manager.getDebugInfo(): object;
|
|
550
|
+
|
|
551
|
+
/** 设置状态变化回调 */
|
|
552
|
+
manager.setStateCallback(callback: StateChangeCallback | null): void;
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### 核心设计
|
|
556
|
+
|
|
557
|
+
1. **稳定容器**:容器在 `document.body` 中创建,激活时移到目标元素内,停用时移回 body 隐藏,不受 React 生命周期影响
|
|
558
|
+
2. **实例缓存**:每个 entry 只 `loadMicroApp` 一次,后续切换复用已有实例(mount/unmount)
|
|
559
|
+
3. **操作序列号**:通过递增的 `operationSeq` 检测过期操作,替代旧的会话 ID 机制
|
|
560
|
+
4. **自动路由守卫**:由独立的 `route-guard.ts` 自动检测用户意图,业务代码无需感知
|
|
561
|
+
|
|
562
|
+
### 快速切换时序
|
|
563
|
+
|
|
564
|
+
```
|
|
565
|
+
场景:A → B → A 快速切换
|
|
566
|
+
|
|
567
|
+
switchTo(A):operationSeq=1,开始 loadMicroApp
|
|
568
|
+
↓
|
|
569
|
+
switchTo(B):operationSeq=2,A 的 pendingRequest 被替换
|
|
570
|
+
↓
|
|
571
|
+
A 的 processRequest 在异步步骤中检测 shouldAbort(mySeq=1) → true
|
|
572
|
+
↓
|
|
573
|
+
A 等待 mountPromise 完成后执行 safeUnmount,容器移回 body
|
|
574
|
+
↓
|
|
575
|
+
B 开始 processRequest,检查缓存 → 无缓存 → loadMicroApp
|
|
576
|
+
↓
|
|
577
|
+
B 加载完成后同步最新 Props(locale/timezone/routePath 等)
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### 设计决策
|
|
581
|
+
|
|
582
|
+
| 决策点 | 选择 | 理由 |
|
|
583
|
+
| --- | --- | --- |
|
|
584
|
+
| 容器策略 | 稳定容器(body 中创建,移动挂载) | 不受 React 生命周期影响,避免容器被意外销毁 |
|
|
585
|
+
| 并发控制 | 操作序列号 + pendingRequest 队列 | 简单高效,新请求自动覆盖旧请求 |
|
|
586
|
+
| 实例缓存 | loadPromise 完成后立即缓存 | 即使被 abort 也可复用,避免重复加载 |
|
|
587
|
+
| unmount 安全 | 等待 mountPromise 完成后再 unmount | 避免 single-spa error #32 |
|
|
588
|
+
| 超时保护 | load 30s / mount 30s / unmount 10s | 平衡等待时间与异常检测速度 |
|
|
589
|
+
| Props 同步 | mount 完成后立即 safeUpdate | 确保加载期间的变化不丢失 |
|