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.
Files changed (159) hide show
  1. package/README.md +199 -15
  2. package/bin/mico.js +232 -27
  3. package/generators/micro-react/index.js +200 -18
  4. package/generators/micro-react/meta.json +13 -0
  5. package/generators/micro-react/templates/.commitlintrc.js +1 -0
  6. package/generators/micro-react/templates/.cursor/rules/always-read-docs.mdc +14 -4
  7. package/generators/micro-react/templates/.cursor/rules/cicd-deploy.mdc +10 -8
  8. package/generators/micro-react/templates/.cursor/rules/coding-conventions.mdc +1 -1
  9. package/generators/micro-react/templates/.cursor/rules/development-guide.mdc +3 -4
  10. package/generators/micro-react/templates/.cursor/rules/layout-app.mdc +38 -31
  11. package/generators/micro-react/templates/.cursor/rules/project-overview.mdc +7 -4
  12. package/generators/micro-react/templates/.cursor/rules/theme-system.mdc +10 -12
  13. package/generators/micro-react/templates/.eslintrc.js +25 -1
  14. package/generators/micro-react/templates/AGENTS.md +5 -2
  15. package/generators/micro-react/templates/CICD/before_build.sh +76 -0
  16. package/generators/micro-react/templates/CICD/start_dev.sh +27 -3
  17. package/generators/micro-react/templates/CICD/start_prod.sh +26 -3
  18. package/generators/micro-react/templates/CICD/start_test.sh +28 -3
  19. package/generators/micro-react/templates/CICD/wangsu_fresh_dev.sh +4 -4
  20. package/generators/micro-react/templates/CICD/wangsu_fresh_prod.sh +4 -4
  21. package/generators/micro-react/templates/CICD/wangsu_fresh_test.sh +4 -4
  22. package/generators/micro-react/templates/CLAUDE.md +16 -9
  23. package/generators/micro-react/templates/README.md +42 -4
  24. package/generators/micro-react/templates/_gitignore +4 -0
  25. package/generators/micro-react/templates/_npmrc +4 -0
  26. package/generators/micro-react/templates/apps/layout/config/config.dev.ts +32 -16
  27. package/generators/micro-react/templates/apps/layout/config/config.prod.development.ts +24 -29
  28. package/generators/micro-react/templates/apps/layout/config/config.prod.testing.ts +25 -6
  29. package/generators/micro-react/templates/apps/layout/config/config.prod.ts +16 -7
  30. package/generators/micro-react/templates/apps/layout/config/config.ts +27 -4
  31. package/generators/micro-react/templates/apps/layout/config/routes.ts +5 -5
  32. 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
  33. package/generators/micro-react/templates/apps/layout/docs/common-intl.md +372 -0
  34. 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
  35. package/generators/micro-react/templates/apps/layout/docs/feature-404/351/241/265/351/235/242.md +103 -0
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. package/generators/micro-react/templates/apps/layout/docs/utils-timezone.md +324 -0
  42. package/generators/micro-react/templates/apps/layout/mock/api.mock.ts +81 -61
  43. package/generators/micro-react/templates/apps/layout/mock/menus.ts +114 -4
  44. package/generators/micro-react/templates/apps/layout/mock/pages.ts +86 -0
  45. package/generators/micro-react/templates/apps/layout/package.json +7 -4
  46. package/generators/micro-react/templates/apps/layout/src/app.tsx +111 -76
  47. package/generators/micro-react/templates/apps/layout/src/common/auth/index.ts +3 -0
  48. package/generators/micro-react/templates/apps/layout/src/common/helpers.ts +177 -0
  49. package/generators/micro-react/templates/apps/layout/src/common/locale.ts +22 -17
  50. package/generators/micro-react/templates/apps/layout/src/common/menu/parser.ts +192 -42
  51. package/generators/micro-react/templates/apps/layout/src/common/menu/types.ts +69 -5
  52. package/generators/micro-react/templates/apps/layout/src/common/micro/index.ts +34 -0
  53. package/generators/micro-react/templates/apps/layout/src/common/micro-prefetch.ts +109 -0
  54. package/generators/micro-react/templates/apps/layout/src/common/portal-data.ts +45 -0
  55. package/generators/micro-react/templates/apps/layout/src/common/request/config.ts +72 -10
  56. package/generators/micro-react/templates/apps/layout/src/common/request/index.ts +2 -2
  57. package/generators/micro-react/templates/apps/layout/src/common/request/interceptors.ts +31 -3
  58. package/generators/micro-react/templates/apps/layout/src/common/request/sso.ts +29 -11
  59. package/generators/micro-react/templates/apps/layout/src/common/request/url-resolver.ts +1 -1
  60. package/generators/micro-react/templates/apps/layout/src/common/route-guard.ts +345 -0
  61. package/generators/micro-react/templates/apps/layout/src/common/theme.ts +2 -4
  62. package/generators/micro-react/templates/apps/layout/src/common/upload/oss.ts +3 -4
  63. package/generators/micro-react/templates/apps/layout/src/common/upload/types.ts +1 -1
  64. package/generators/micro-react/templates/apps/layout/src/common/uploadFiles.ts +1 -1
  65. package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.less +8 -3
  66. package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.tsx +25 -8
  67. package/generators/micro-react/templates/apps/layout/src/components/HeaderDropdown/index.tsx +20 -0
  68. package/generators/micro-react/templates/apps/layout/src/components/IconFont/index.tsx +5 -6
  69. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.less +21 -6
  70. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +83 -149
  71. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/micro-app-manager.ts +569 -0
  72. package/generators/micro-react/templates/apps/layout/src/components/RightContent/AvatarDropdown.tsx +383 -0
  73. package/generators/micro-react/templates/apps/layout/src/components/RightContent/avatar-dropdown.less +35 -0
  74. package/generators/micro-react/templates/apps/layout/src/components/RightContent/index.ts +2 -0
  75. package/generators/micro-react/templates/apps/layout/src/constants/index.ts +170 -6
  76. package/generators/micro-react/templates/apps/layout/src/global.less +18 -9
  77. package/generators/micro-react/templates/apps/layout/src/hooks/useMenu.ts +3 -2
  78. package/generators/micro-react/templates/apps/layout/src/hooks/useRoutePermissionRefresh.ts +72 -0
  79. package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.less +3 -1
  80. package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.tsx +10 -55
  81. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +34 -4
  82. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +24 -8
  83. package/generators/micro-react/templates/apps/layout/src/layouts/index.less +84 -13
  84. package/generators/micro-react/templates/apps/layout/src/layouts/index.tsx +156 -69
  85. package/generators/micro-react/templates/apps/layout/src/locales/en-US.ts +12 -0
  86. package/generators/micro-react/templates/apps/layout/src/locales/zh-CN.ts +12 -0
  87. package/generators/micro-react/templates/apps/layout/src/pages/403/index.tsx +8 -2
  88. package/generators/micro-react/templates/apps/layout/src/pages/404/index.tsx +78 -0
  89. package/generators/micro-react/templates/apps/layout/src/pages/Home/index.less +3 -0
  90. package/generators/micro-react/templates/apps/layout/src/pages/Home/index.tsx +7 -1
  91. package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.less +1 -1
  92. package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.tsx +3 -3
  93. package/generators/micro-react/templates/apps/layout/src/requestErrorConfig.ts +1 -1
  94. package/generators/micro-react/templates/apps/layout/src/services/config/index.ts +63 -0
  95. package/generators/micro-react/templates/apps/layout/src/services/config/type.ts +30 -0
  96. package/generators/micro-react/templates/apps/layout/src/services/user.ts +29 -2
  97. package/generators/micro-react/templates/apps/layout/tailwind.config.js +3 -0
  98. package/generators/micro-react/templates/deployDesc.md +3 -3
  99. package/generators/micro-react/templates/dev.preset.json +14 -0
  100. package/generators/micro-react/templates/docs/dev-preset.md +130 -0
  101. package/generators/micro-react/templates/package.json +21 -6
  102. package/generators/micro-react/templates/packages/common-intl/README.md +427 -0
  103. package/generators/micro-react/templates/packages/common-intl/package.json +34 -0
  104. package/generators/micro-react/templates/packages/common-intl/src/index.ts +7 -0
  105. package/generators/micro-react/templates/packages/common-intl/src/indexedDBUtils.ts +51 -0
  106. package/generators/micro-react/templates/packages/common-intl/src/intl.ts +50 -0
  107. package/generators/micro-react/templates/packages/common-intl/src/utils.ts +482 -0
  108. package/generators/micro-react/templates/packages/common-intl/tsconfig.json +22 -0
  109. package/generators/micro-react/templates/packages/common-intl/vite.config.ts +25 -0
  110. package/generators/micro-react/templates/scripts/apply-sentry-plugin.ts +45 -0
  111. package/generators/micro-react/templates/scripts/collect-dist.js +10 -0
  112. package/generators/micro-react/templates/scripts/dev-preset.js +265 -0
  113. package/generators/micro-react/templates/scripts/dev-preset.schema.json +39 -0
  114. package/generators/micro-react/templates/turbo.json +4 -1
  115. package/generators/subapp-react/index.js +326 -40
  116. package/generators/subapp-react/meta.json +10 -0
  117. package/generators/subapp-react/templates/homepage/.env +2 -1
  118. package/generators/subapp-react/templates/homepage/README.md +3 -3
  119. package/generators/subapp-react/templates/homepage/config/config.dev.ts +14 -7
  120. package/generators/subapp-react/templates/homepage/config/config.prod.development.ts +16 -5
  121. package/generators/subapp-react/templates/homepage/config/config.prod.testing.ts +16 -5
  122. package/generators/subapp-react/templates/homepage/config/config.prod.ts +14 -5
  123. package/generators/subapp-react/templates/homepage/config/config.ts +21 -0
  124. package/generators/subapp-react/templates/homepage/config/routes.ts +2 -2
  125. package/generators/subapp-react/templates/homepage/mock/api.mock.ts +2 -2
  126. package/generators/subapp-react/templates/homepage/package.json +7 -4
  127. package/generators/subapp-react/templates/homepage/src/app.tsx +18 -27
  128. package/generators/subapp-react/templates/homepage/src/common/request.ts +29 -2
  129. package/generators/subapp-react/templates/homepage/src/global.less +6 -5
  130. package/generators/subapp-react/templates/homepage/src/pages/index.less +3 -3
  131. package/generators/subapp-react/templates/homepage/src/pages/index.tsx +99 -60
  132. package/generators/subapp-react/templates/homepage/src/styles/theme.less +1 -1
  133. package/generators/subapp-umd/ignore-list.json +5 -0
  134. package/generators/subapp-umd/index.js +309 -0
  135. package/generators/subapp-umd/meta.json +11 -0
  136. package/generators/subapp-umd/templates/README.md +94 -0
  137. package/generators/subapp-umd/templates/package.json +35 -0
  138. package/generators/subapp-umd/templates/public/index.html +34 -0
  139. package/generators/subapp-umd/templates/src/App.less +15 -0
  140. package/generators/subapp-umd/templates/src/App.tsx +13 -0
  141. package/generators/subapp-umd/templates/src/index.ts +2 -0
  142. package/generators/subapp-umd/templates/tsconfig.json +27 -0
  143. package/generators/subapp-umd/templates/webpack.config.js +70 -0
  144. package/lib/utils.js +332 -2
  145. package/package.json +15 -2
  146. package/generators/micro-react/templates/apps/layout/mock/menus.json +0 -100
  147. package/generators/micro-react/templates/apps/layout/src/common/constants.ts +0 -38
  148. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/container-manager.ts +0 -202
  149. package/generators/micro-react/templates/packages/shared-styles/README.md +0 -124
  150. package/generators/micro-react/templates/packages/shared-styles/arco-design-mobile-override.less +0 -91
  151. package/generators/micro-react/templates/packages/shared-styles/arco-override.less +0 -119
  152. package/generators/micro-react/templates/packages/shared-styles/index.d.ts +0 -44
  153. package/generators/micro-react/templates/packages/shared-styles/index.less +0 -13
  154. package/generators/micro-react/templates/packages/shared-styles/package.json +0 -30
  155. package/generators/micro-react/templates/packages/shared-styles/theme-inject.less +0 -10
  156. package/generators/micro-react/templates/packages/shared-styles/themes/dark/custom-var.less +0 -290
  157. package/generators/micro-react/templates/packages/shared-styles/themes/normal/custom-var.less +0 -269
  158. package/generators/micro-react/templates/packages/shared-styles/variables-only.less +0 -433
  159. package/generators/micro-react/templates/packages/shared-styles/variables.less +0 -452
@@ -1,7 +1,7 @@
1
- import { findRouteByPath } from '@/common/menu';
2
- import { NO_AUTH_ROUTE_LIST } from '@/constants';
1
+ import { findRouteByPath, getMenuLabel, isChineseLocale } from '@/common/menu';
2
+ import { isNoLayoutRoute } from '@/constants';
3
3
  import useMenu from '@/hooks/useMenu';
4
- import { Tabs } from '@arco-design/web-react';
4
+ import { Tabs } from '@mico-platform/ui';
5
5
  import { history, useLocation } from '@umijs/max';
6
6
  import { useEffect, useMemo, useState } from 'react';
7
7
  import './index.less';
@@ -9,7 +9,12 @@ import './index.less';
9
9
  const TabPane = Tabs.TabPane;
10
10
 
11
11
  interface TabItem {
12
+ /** 菜单显示名称(中文) */
12
13
  title: string;
14
+ /** 菜单显示名称(英文) */
15
+ titleEn?: string;
16
+ /** 国际化 key */
17
+ nameKey?: string;
13
18
  key: string;
14
19
  path: string;
15
20
  icon?: string;
@@ -47,7 +52,7 @@ function AppTabs() {
47
52
  const [tabs, setTabs] = useState<TabItem[]>([]);
48
53
 
49
54
  const showTabs = useMemo(() => {
50
- return !NO_AUTH_ROUTE_LIST.includes(location.pathname);
55
+ return !isNoLayoutRoute(location.pathname);
51
56
  }, [location.pathname]);
52
57
 
53
58
  const microAppPrefixes = useMemo(() => {
@@ -110,6 +115,8 @@ function AppTabs() {
110
115
  if (!existingTab) {
111
116
  const newTab: TabItem = {
112
117
  title: currentRoute.name,
118
+ titleEn: currentRoute.nameEn,
119
+ nameKey: currentRoute.nameKey,
113
120
  key: tabKey,
114
121
  path: tabPath,
115
122
  icon: currentRoute.icon,
@@ -120,7 +127,12 @@ function AppTabs() {
120
127
 
121
128
  return prevTabs.map((tab) => {
122
129
  if (shouldReuseTab(tab.path, actualPath)) {
123
- return { ...tab, title: currentRoute.name };
130
+ return {
131
+ ...tab,
132
+ title: currentRoute.name,
133
+ titleEn: currentRoute.nameEn,
134
+ nameKey: currentRoute.nameKey,
135
+ };
124
136
  }
125
137
  return tab;
126
138
  });
@@ -174,9 +186,14 @@ function AppTabs() {
174
186
  onDeleteTab={handleDeleteTab}
175
187
  onChange={handleTabChange}
176
188
  >
177
- {tabs.map((tab) => (
178
- <TabPane destroyOnHide key={tab.key} title={tab.title} />
179
- ))}
189
+ {tabs.map((tab) => {
190
+ const isChinese = isChineseLocale();
191
+ const label = getMenuLabel(
192
+ { name: tab.title, nameEn: tab.titleEn, nameKey: tab.nameKey },
193
+ isChinese,
194
+ );
195
+ return <TabPane destroyOnHide key={tab.key} title={label} />;
196
+ })}
180
197
  </Tabs>
181
198
  );
182
199
  }
@@ -0,0 +1,20 @@
1
+ import { Dropdown, type DropdownProps } from '@mico-platform/ui';
2
+ import React from 'react';
3
+
4
+ export type HeaderDropdownProps = {
5
+ placement?:
6
+ | 'bottomLeft'
7
+ | 'bottomRight'
8
+ | 'topLeft'
9
+ | 'topCenter'
10
+ | 'topRight'
11
+ | 'bottomCenter';
12
+ } & Omit<DropdownProps, 'overlay'>;
13
+
14
+ const HeaderDropdown: React.FC<HeaderDropdownProps> = ({
15
+ ...restProps
16
+ }) => {
17
+ return <Dropdown {...restProps} />;
18
+ };
19
+
20
+ export default HeaderDropdown;
@@ -1,5 +1,5 @@
1
- import { getCurrentLocale, getIconFontPath } from '@/common/locale';
2
- import { Icon } from '@arco-design/web-react';
1
+ import { getIconFontPath } from '@/common/locale';
2
+ import { Icon } from '@mico-platform/ui';
3
3
 
4
4
  // 该组件用于自定义的图标,用法见https://arco.design/react/components/icon#%E6%B7%BB%E5%8A%A0-iconbox-%E9%A1%B9%E7%9B%AE
5
5
  // 图标的名称可以在设计图ued里面找到 https://www.figma.com/design/skTJZPfwLCDgEV9JC6wzpP/%E5%AE%A2%E6%9C%8D%E4%B8%AD%E5%BF%83_%E4%BC%9A%E8%AF%9D%E7%AE%A1%E7%90%86_%E5%B7%A5%E4%BD%9C%E5%8F%B0?node-id=647-4835&t=8swGel7i3bPnKkul-0
@@ -7,13 +7,12 @@ import { Icon } from '@arco-design/web-react';
7
7
  // 字体库地址:https://arco.design/iconbox/mime/lib/1945/0
8
8
 
9
9
  /**
10
- * 根据当前语言加载对应的图标库
10
+ * 根据当前语言加载对应的图标库(当前只有中文)
11
11
  * 语言切换时会重新加载页面,所以这里只需要在初始化时根据当前语言加载
12
12
  */
13
13
  function createIconFont() {
14
- // 获取当前语言(按优先级:URL参数 > localStorage > 浏览器默认)
15
- const currentLocale = getCurrentLocale();
16
- const iconPath = getIconFontPath(currentLocale);
14
+ // TODO: 后续支持多语言时,需要根据当前语言加载对应的图标库
15
+ const iconPath = getIconFontPath();
17
16
 
18
17
  // 创建 IconFont 实例
19
18
  return Icon.addFromIconFontCn({ src: iconPath });
@@ -4,20 +4,17 @@
4
4
 
5
5
  .micro-app-container {
6
6
  width: 100%;
7
- height: 100%;
8
7
  position: relative;
8
+ display: flex;
9
+ flex-direction: column;
9
10
  overflow: auto;
10
11
  }
11
12
 
12
13
  .micro-app-loading {
13
- position: absolute;
14
- top: 0;
15
- left: 0;
16
- right: 0;
17
- bottom: 0;
18
14
  display: flex;
19
15
  align-items: center;
20
16
  justify-content: center;
17
+ min-height: 600px;
21
18
  background: var(--color-bg-1);
22
19
  z-index: 10;
23
20
  }
@@ -48,10 +45,28 @@
48
45
  // 激活时在文档流中,继承占位元素的尺寸
49
46
  width: 100%;
50
47
  height: 100%;
48
+ display: flex;
49
+ flex: 1;
50
+ flex-direction: column;
51
51
  overflow: auto;
52
+ min-height: calc(100vh - 134px);
53
+
52
54
 
53
55
  > div {
56
+ flex: 1;
57
+ display: flex;
58
+ flex-direction: column;
59
+ }
60
+
61
+ > div > div {
54
62
  height: 100%;
63
+ display: flex;
64
+ flex: 1 1;
65
+ }
66
+
67
+ > div > div > div {
68
+ width: 100%;
69
+ flex: 1 1;
55
70
  }
56
71
 
57
72
  // 隐藏状态(在 body 中)
@@ -1,20 +1,18 @@
1
1
  import { getAuthInfo } from '@/common/auth/auth-manager';
2
2
  import { EEnv, getEnv } from '@/common/env';
3
+ import { getCurrentLocale } from '@/common/locale';
3
4
  import { request } from '@/common/request';
4
- import { Spin } from '@arco-design/web-react';
5
- import { loadMicroApp } from 'qiankun';
6
- import React, { useEffect, useMemo, useRef, useState } from 'react';
7
- import {
8
- activateContainer,
9
- deactivateContainer,
10
- getContainer,
11
- getMicroApp,
12
- setMicroApp,
13
- unmountApp,
14
- } from './container-manager';
5
+ import { isPageAuthFree } from '@/common/menu/parser';
6
+ import { isAuthDisabled, isNoAuthRoute, isNoPermissionRoute } from '@/constants';
7
+ import { Spin } from '@mico-platform/ui';
8
+ import { useLocation, useModel } from '@umijs/max';
9
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
15
10
  import './index.less';
11
+ import { microAppManager, type MicroAppState } from './micro-app-manager';
16
12
 
17
13
  interface MicroAppLoaderProps {
14
+ /** 微应用在主应用中的挂载路径前缀(来自 ParsedRoute.base / 页面配置 base),经 normalizeMicroAppBase 后传给子应用 */
15
+ base: string;
18
16
  entry: string;
19
17
  name: string;
20
18
  displayName?: string;
@@ -22,6 +20,10 @@ interface MicroAppLoaderProps {
22
20
  routePath?: string;
23
21
  }
24
22
 
23
+ /** 微应用 base:先去掉末尾 /,再去掉末尾 *(与路由 path 约定一致) */
24
+ export const normalizeMicroAppBase = (path: string): string =>
25
+ path.replace(/\/+$/, '').replace(/\*+$/, '');
26
+
25
27
  const sanitizeId = (path: string): string => {
26
28
  return (
27
29
  path
@@ -32,17 +34,34 @@ const sanitizeId = (path: string): string => {
32
34
  );
33
35
  };
34
36
 
37
+ /**
38
+ * 微应用加载器
39
+ *
40
+ * 使用 MicroAppManager 统一管理微应用的加载和卸载。
41
+ * 用户意图追踪在 MicroAppManager 内部处理。
42
+ */
35
43
  const MicroAppLoader: React.FC<MicroAppLoaderProps> = ({
44
+ base,
36
45
  entry,
37
46
  name,
38
47
  displayName,
39
48
  routePath,
40
49
  }) => {
41
50
  const wrapperRef = useRef<HTMLDivElement>(null);
42
- const mountIdRef = useRef(0);
43
- const [loading, setLoading] = useState(true);
44
- const [error, setError] = useState<string | null>(null);
45
- const isMountedRef = useRef(false);
51
+ const [state, setState] = useState<MicroAppState>({
52
+ loading: true,
53
+ error: null,
54
+ mounted: false,
55
+ });
56
+
57
+ const { initialState } = useModel('@@initialState');
58
+ const location = useLocation();
59
+ const isAuthReady =
60
+ isAuthDisabled() ||
61
+ isPageAuthFree(location.pathname) ||
62
+ isNoAuthRoute(location.pathname) ||
63
+ isNoPermissionRoute(location.pathname) ||
64
+ !!initialState?.currentUser;
46
65
 
47
66
  const appName = sanitizeId(name);
48
67
 
@@ -55,173 +74,88 @@ const MicroAppLoader: React.FC<MicroAppLoaderProps> = ({
55
74
  : 'production';
56
75
  }, []);
57
76
 
58
- // 使用 ref 存储构建 props 的函数,避免 effect 依赖变化导致微应用重新加载
59
- const buildPropsRef = useRef(() => ({}));
60
- buildPropsRef.current = () => {
77
+ // 构建传递给子应用的 props
78
+ const buildProps = useCallback(() => {
61
79
  const authInfo = getAuthInfo();
62
80
  return {
63
- mainApp: 'portal-web',
81
+ mainApp: '<%= projectName %>',
64
82
  env,
65
83
  authToken: authInfo.token,
66
84
  uid: authInfo.uid,
67
85
  avatar: authInfo.avatar,
68
86
  nickname: authInfo.nickname,
87
+ base: normalizeMicroAppBase(base || '/'),
69
88
  // 传递当前路由路径,让子应用进行内部路由切换
70
89
  routePath,
71
90
  // 传递主应用的 request 实例,子应用可直接使用
72
91
  request,
92
+ // 传递当前多语言类型给子应用(zh-CN, en-US)
93
+ locale: getCurrentLocale(),
73
94
  };
74
- };
95
+ }, [base, env, routePath]);
75
96
 
76
- // 当路由等"无需重载"的状态更新时,通过 update() 通知子应用
77
- useEffect(() => {
78
- if (!isMountedRef.current) return;
97
+ // ref 持有最新的 buildProps,避免加载 effect 依赖它导致子应用被重载
98
+ const buildPropsRef = useRef(buildProps);
99
+ buildPropsRef.current = buildProps;
79
100
 
80
- const microApp = getMicroApp(appName);
81
- microApp?.update?.(buildPropsRef.current());
82
- }, [appName, routePath]);
101
+ // props 变化时,通知子应用更新(不重新加载)
102
+ useEffect(() => {
103
+ if (state.mounted) {
104
+ microAppManager.updateProps(buildProps());
105
+ }
106
+ }, [state.mounted, buildProps]);
83
107
 
108
+ // 加载微应用(只在 entry/appName/isAuthReady 变化时触发)
84
109
  useEffect(() => {
85
110
  const wrapper = wrapperRef.current;
86
- if (!wrapper) return;
87
-
88
- const currentMountId = ++mountIdRef.current;
89
- let isCancelled = false;
90
-
91
- setLoading(true);
92
- setError(null);
93
-
94
- const container = getContainer(appName);
95
- activateContainer(appName, wrapper);
96
-
97
- const loadApp = async () => {
98
- // 卸载旧实例
99
- const existingApp = getMicroApp(appName);
100
- if (existingApp) {
101
- try {
102
- await existingApp.unmount();
103
- } catch {
104
- // 忽略
105
- }
106
- }
107
-
108
- if (isCancelled) return;
109
-
110
- try {
111
- const microApp = loadMicroApp(
112
- {
113
- name: `${appName}_${currentMountId}`,
114
- entry,
115
- container,
116
- props: buildPropsRef.current(),
117
- },
118
- {
119
- sandbox: { loose: true },
120
- // 自定义 fetch,包装原生 fetch 以便在网络层面捕获错误
121
- fetch: async (url, options) => {
122
- try {
123
- const response = await window.fetch(url, options);
124
- if (!response.ok) {
125
- throw new Error(
126
- `HTTP ${response.status}: ${response.statusText}`,
127
- );
128
- }
129
- return response;
130
- } catch (err) {
131
- // 将网络错误转换为更友好的错误信息
132
- const message =
133
- err instanceof Error ? err.message : 'Network error';
134
- throw new Error(`加载资源失败 (${url}): ${message}`);
135
- }
136
- },
137
- },
138
- );
139
-
140
- setMicroApp(appName, microApp);
141
-
142
- // 关键:必须同时处理 loadPromise 和 bootstrapPromise/mountPromise 的错误
143
- // qiankun 内部会产生多个 Promise 链,任何一个未处理的 rejection 都会导致页面崩溃
144
- const handlePromiseError = (err: unknown) => {
145
- if (!isCancelled) {
146
- const message =
147
- err instanceof Error ? err.message : 'Unknown error';
148
- setError(message);
149
- setLoading(false);
150
- }
151
- };
152
-
153
- // 为所有 qiankun 返回的 Promise 添加错误处理器
154
- microApp.loadPromise.catch(handlePromiseError);
155
- microApp.bootstrapPromise.catch(handlePromiseError);
156
- microApp.mountPromise.catch(handlePromiseError);
157
-
158
- if (isCancelled) {
159
- unmountApp(appName);
160
- return;
161
- }
162
-
163
- // 等待加载完成,这里的错误会被上层 catch 捕获
164
- await microApp.loadPromise;
165
-
166
- if (isCancelled) {
167
- unmountApp(appName);
168
- return;
169
- }
170
-
171
- // 等待挂载完成
172
- await microApp.mountPromise;
173
-
174
- if (!isCancelled) {
175
- isMountedRef.current = true;
176
- setLoading(false);
177
- }
178
- } catch (err) {
179
- if (!isCancelled) {
180
- const message = err instanceof Error ? err.message : 'Unknown error';
181
- // 提取更友好的错误信息
182
- const friendlyMessage = message.includes('Failed to fetch')
183
- ? '无法连接到子应用服务,请检查子应用是否已启动'
184
- : message;
185
- setError(friendlyMessage);
186
- setLoading(false);
187
- }
188
- }
189
- };
190
-
191
- loadApp();
111
+ if (!wrapper) {
112
+ console.warn('[MicroAppLoader] wrapper is null, skip loading');
113
+ return;
114
+ }
115
+
116
+ // 等待认证信息准备好
117
+ if (!isAuthReady) {
118
+ console.log('[MicroAppLoader] waiting for auth ready:', { appName, entry });
119
+ return;
120
+ }
121
+
122
+ console.log('🔍[路由调试] MicroAppLoader useEffect 执行', { appName, entry });
123
+
124
+ // 设置状态回调
125
+ microAppManager.setStateCallback(setState);
126
+
127
+ // 切换到目标微应用
128
+ microAppManager.switchTo({
129
+ name: appName,
130
+ entry,
131
+ target: wrapper,
132
+ props: buildPropsRef.current(),
133
+ });
192
134
 
193
135
  return () => {
194
- isCancelled = true;
195
- isMountedRef.current = false;
196
-
197
- // 同步执行,确保在下一次 activate 前移走容器
198
- deactivateContainer(appName);
199
-
200
- // 异步卸载微应用,给 qiankun 足够时间完成清理
201
- requestAnimationFrame(() => {
202
- unmountApp(appName);
203
- });
136
+ console.log('🔍[路由调试] MicroAppLoader cleanup', { appName });
137
+ microAppManager.cancel();
138
+ microAppManager.setStateCallback(null);
204
139
  };
205
- // 注意:不依赖 sharedServices,websocket 变化时通过 update() 更新 props 而不重新加载微应用
206
- }, [entry, appName, env]);
140
+ }, [entry, appName, isAuthReady, buildProps]);
207
141
 
208
142
  return (
209
143
  <div className="micro-app-container">
210
- {error && (
144
+ {state.error && (
211
145
  <div className="micro-app-error">
212
146
  <p>微应用加载失败</p>
213
- <p className="error-detail">{error}</p>
147
+ <p className="error-detail">{state.error}</p>
214
148
  </div>
215
149
  )}
216
- {loading && !error && (
150
+ {state.loading && !state.error && (
217
151
  <div className="micro-app-loading">
218
152
  <Spin dot tip={`正在加载 ${displayName || name}...`} />
219
153
  </div>
220
154
  )}
221
- {/* qiankun 容器挂载点,error 时隐藏 */}
155
+ {/* qiankun 容器挂载点 */}
222
156
  <div
223
157
  ref={wrapperRef}
224
- style={{ display: error ? 'none' : 'block', height: '100%' }}
158
+ style={{ display: state.error ? 'none' : 'block', height: '100%' }}
225
159
  />
226
160
  </div>
227
161
  );