generator-mico-cli 0.2.21 → 0.2.23

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 (68) hide show
  1. package/README.md +33 -0
  2. package/bin/mico.js +15 -2
  3. package/generators/micro-react/index.js +44 -6
  4. package/generators/micro-react/meta.json +2 -1
  5. package/generators/micro-react/templates/.cursor/rules/always-read-docs.mdc +14 -4
  6. package/generators/micro-react/templates/.cursor/rules/layout-app.mdc +36 -26
  7. package/generators/micro-react/templates/.cursor/rules/project-overview.mdc +5 -2
  8. package/generators/micro-react/templates/CLAUDE.md +4 -2
  9. package/generators/micro-react/templates/_gitignore +3 -1
  10. package/generators/micro-react/templates/_npmrc +1 -0
  11. package/generators/micro-react/templates/apps/layout/config/config.dev.ts +7 -3
  12. package/generators/micro-react/templates/apps/layout/config/config.prod.development.ts +5 -0
  13. package/generators/micro-react/templates/apps/layout/config/config.prod.testing.ts +5 -0
  14. package/generators/micro-react/templates/apps/layout/config/config.prod.ts +12 -0
  15. package/generators/micro-react/templates/apps/layout/config/routes.ts +0 -5
  16. 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 +4 -2
  17. 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 +116 -56
  18. 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
  19. package/generators/micro-react/templates/apps/layout/mock/api.mock.ts +81 -61
  20. package/generators/micro-react/templates/apps/layout/mock/menus.ts +89 -144
  21. package/generators/micro-react/templates/apps/layout/mock/pages.ts +83 -0
  22. package/generators/micro-react/templates/apps/layout/package.json +1 -0
  23. package/generators/micro-react/templates/apps/layout/src/app.tsx +13 -8
  24. package/generators/micro-react/templates/apps/layout/src/common/menu/parser.ts +118 -43
  25. package/generators/micro-react/templates/apps/layout/src/common/menu/types.ts +31 -4
  26. package/generators/micro-react/templates/apps/layout/src/common/micro-prefetch.ts +3 -2
  27. package/generators/micro-react/templates/apps/layout/src/common/portal-data.ts +45 -0
  28. package/generators/micro-react/templates/apps/layout/src/common/request/config.ts +49 -10
  29. package/generators/micro-react/templates/apps/layout/src/common/request/interceptors.ts +1 -1
  30. package/generators/micro-react/templates/apps/layout/src/common/request/sso.ts +6 -0
  31. package/generators/micro-react/templates/apps/layout/src/common/theme.ts +0 -2
  32. package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.less +0 -1
  33. package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.tsx +4 -4
  34. package/generators/micro-react/templates/apps/layout/src/components/IconFont/index.tsx +4 -5
  35. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.less +21 -6
  36. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +4 -3
  37. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/micro-app-manager.ts +7 -1
  38. package/generators/micro-react/templates/apps/layout/src/components/RightContent/AvatarDropdown.tsx +12 -16
  39. package/generators/micro-react/templates/apps/layout/src/global.less +15 -2
  40. package/generators/micro-react/templates/apps/layout/src/hooks/useMenu.ts +3 -2
  41. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +32 -4
  42. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +20 -10
  43. package/generators/micro-react/templates/apps/layout/src/layouts/index.tsx +75 -38
  44. package/generators/micro-react/templates/apps/layout/src/pages/404/index.tsx +3 -7
  45. package/generators/micro-react/templates/apps/layout/src/services/user.ts +7 -3
  46. package/generators/micro-react/templates/dev.preset.json +1 -1
  47. package/generators/micro-react/templates/package.json +1 -0
  48. package/generators/micro-react/templates/scripts/apply-sentry-plugin.ts +45 -0
  49. package/generators/subapp-react/index.js +206 -6
  50. package/generators/subapp-react/templates/homepage/.env +2 -1
  51. package/generators/subapp-react/templates/homepage/config/config.prod.development.ts +1 -0
  52. package/generators/subapp-react/templates/homepage/config/config.prod.testing.ts +1 -0
  53. package/generators/subapp-react/templates/homepage/config/config.prod.ts +8 -0
  54. package/generators/subapp-react/templates/homepage/package.json +1 -0
  55. package/generators/subapp-react/templates/homepage/src/app.tsx +6 -0
  56. package/generators/subapp-umd/ignore-list.json +5 -0
  57. package/generators/subapp-umd/index.js +325 -0
  58. package/generators/subapp-umd/meta.json +11 -0
  59. package/generators/subapp-umd/templates/README.md +94 -0
  60. package/generators/subapp-umd/templates/package.json +35 -0
  61. package/generators/subapp-umd/templates/public/index.html +34 -0
  62. package/generators/subapp-umd/templates/src/App.less +15 -0
  63. package/generators/subapp-umd/templates/src/App.tsx +13 -0
  64. package/generators/subapp-umd/templates/src/index.ts +2 -0
  65. package/generators/subapp-umd/templates/tsconfig.json +27 -0
  66. package/generators/subapp-umd/templates/webpack.config.js +68 -0
  67. package/lib/utils.js +2 -1
  68. package/package.json +1 -1
package/README.md CHANGED
@@ -9,6 +9,7 @@
9
9
  | [docs/mico-cli.md](docs/mico-cli.md) | Mico CLI 功能概述与技术方案 |
10
10
  | [docs/micro-react-generator.md](docs/micro-react-generator.md) | Monorepo 项目生成器说明 |
11
11
  | [docs/subapp-react-generator.md](docs/subapp-react-generator.md) | React 子应用生成器说明 |
12
+ | [docs/subapp-umd-generator.md](docs/subapp-umd-generator.md) | UMD 组件包生成器说明 |
12
13
 
13
14
  ## 要求
14
15
 
@@ -97,6 +98,7 @@ mico create micro-react
97
98
  - @mico-platform/ui、@mico-platform/theme
98
99
  - Turborepo + pnpm Workspace
99
100
  - Husky + Commitlint
101
+ - @common-web/sentry 错误监控与 SourceMap 上传
100
102
 
101
103
  ## React 子应用生成器
102
104
 
@@ -108,6 +110,34 @@ cd <monorepo-root>
108
110
  mico create subapp-react
109
111
  ```
110
112
 
113
+ ## UMD 组件包生成器
114
+
115
+ 在 Monorepo 的 `packages/` 目录下创建 UMD 格式的组件包,使用 Webpack 构建。适用于通过 `<script>` 标签加载的场景(如主应用菜单挂载组件、第三方系统嵌入 Widget 等)。
116
+
117
+ ```bash
118
+ cd <monorepo-root>
119
+ mico create subapp-umd
120
+ ```
121
+
122
+ 生成器会提示输入:
123
+ - **Package name** — 包名(如 `my-widget`)
124
+ - **UMD global variable name** — 全局变量名(如 `MyWidget`)
125
+ - **Package scope** — 包作用域(自动从根 `package.json` 检测)
126
+ - **Dev server port** — 开发端口(默认 `9100`)
127
+
128
+ 生成的包支持:
129
+ - `pnpm dev` — 启动 webpack-dev-server,同时提供 HTML 预览页和 UMD JS 文件
130
+ - `pnpm build` — 构建生产环境 UMD 产物到 `dist/`
131
+
132
+ 开发模式下:
133
+
134
+ | URL | 用途 |
135
+ |---|---|
136
+ | `http://localhost:<port>/` | HTML 预览页,独立调试 |
137
+ | `http://localhost:<port>/<name>.umd.js` | UMD JS 文件,供主应用通过 `jsUrls` 联调 |
138
+
139
+ DevTools Sources 面板中可在 `webpack://<name>/src/` 下定位原始 TypeScript 源码进行断点调试。
140
+
111
141
  ## 本地调试
112
142
 
113
143
  克隆项目后,执行以下步骤进行本地开发和调试:
@@ -133,6 +163,9 @@ mico create micro-react
133
163
 
134
164
  # 测试 subapp-react 生成器(需在已有 monorepo 中执行)
135
165
  mico create subapp-react
166
+
167
+ # 测试 subapp-umd 生成器(需在已有 monorepo 中执行)
168
+ mico create subapp-umd
136
169
  ```
137
170
 
138
171
  调试完成后,可以取消全局链接:
package/bin/mico.js CHANGED
@@ -29,12 +29,14 @@ Options:
29
29
  --version, -v Show version number
30
30
  --verbose Show detailed output during generation
31
31
  --dry-run Preview files without creating them
32
+ --force Overwrite all existing files without confirmation
32
33
  --no-update-check Skip update check
33
34
 
34
35
  Examples:
35
36
  mico create subapp-react
36
37
  mico create micro-react --verbose
37
38
  mico create micro-react --dry-run
39
+ mico create micro-react --force
38
40
  mico list
39
41
  mico update
40
42
  mico doctor
@@ -350,6 +352,7 @@ function performUpdate(latestVersion) {
350
352
  * @param {object} options - 选项
351
353
  * @param {boolean} options.verbose - 是否启用详细输出
352
354
  * @param {boolean} options.dryRun - 是否启用 dry-run 模式
355
+ * @param {boolean} options.force - 是否强制覆盖已有文件
353
356
  */
354
357
  function runGenerator(generator, rest, passthroughArgs, options = {}) {
355
358
  const localGeneratorEntry = path.join(
@@ -374,6 +377,10 @@ function runGenerator(generator, rest, passthroughArgs, options = {}) {
374
377
  yoArgs.push('--dry-run');
375
378
  }
376
379
 
380
+ if (options.force) {
381
+ yoArgs.push('--force');
382
+ }
383
+
377
384
  if (passthroughArgs.length > 0) {
378
385
  yoArgs.push('--', ...passthroughArgs);
379
386
  }
@@ -394,6 +401,9 @@ function runGenerator(generator, rest, passthroughArgs, options = {}) {
394
401
  if (options.dryRun) {
395
402
  console.log(' \x1b[2m[verbose] Dry-run mode enabled\x1b[0m');
396
403
  }
404
+ if (options.force) {
405
+ console.log(' \x1b[2m[verbose] Force mode enabled\x1b[0m');
406
+ }
397
407
  console.log('');
398
408
  }
399
409
 
@@ -432,6 +442,7 @@ async function main() {
432
442
  const skipUpdateCheck = mainArgs.includes('--no-update-check');
433
443
  const isVerbose = mainArgs.includes('--verbose');
434
444
  const isDryRun = mainArgs.includes('--dry-run');
445
+ const isForce = mainArgs.includes('--force');
435
446
 
436
447
  // 过滤掉标志参数
437
448
  const filteredArgs = mainArgs.filter(
@@ -442,7 +453,8 @@ async function main() {
442
453
  arg !== '-v' &&
443
454
  arg !== '--no-update-check' &&
444
455
  arg !== '--verbose' &&
445
- arg !== '--dry-run'
456
+ arg !== '--dry-run' &&
457
+ arg !== '--force'
446
458
  );
447
459
 
448
460
  // 处理 --version
@@ -514,7 +526,8 @@ async function main() {
514
526
  // 运行生成器
515
527
  runGenerator(generator, rest.slice(1), passthroughArgs, {
516
528
  verbose: isVerbose,
517
- dryRun: isDryRun
529
+ dryRun: isDryRun,
530
+ force: isForce
518
531
  });
519
532
  return;
520
533
  }
@@ -36,9 +36,9 @@ module.exports = class extends Generator {
36
36
  this.logger.verbose('Config:', JSON.stringify(rcConfig, null, 2));
37
37
  }
38
38
 
39
- // 检查当前目录是否已是一个 monorepo
39
+ // 检查当前目录是否已是一个 monorepo(--force 跳过此检查)
40
40
  const workspaceFile = path.join(this.projectRoot, 'pnpm-workspace.yaml');
41
- if (fs.existsSync(workspaceFile)) {
41
+ if (fs.existsSync(workspaceFile) && !this.options.force) {
42
42
  console.error('');
43
43
  console.error('❌ Error: Current directory is already a monorepo.');
44
44
  console.error('');
@@ -51,6 +51,9 @@ module.exports = class extends Generator {
51
51
  console.error(' mkdir my-project && cd my-project');
52
52
  console.error(' mico create micro-react');
53
53
  console.error('');
54
+ console.error(' To regenerate in an existing monorepo, use --force:');
55
+ console.error(' mico create micro-react --force');
56
+ console.error('');
54
57
  process.exit(1);
55
58
  }
56
59
  }
@@ -278,9 +281,31 @@ module.exports = class extends Generator {
278
281
 
279
282
  this.log('');
280
283
  this.log('📦 正在安装依赖...');
281
- this.spawnCommandSync('pnpm', ['install'], {
282
- cwd: this.destDir,
283
- });
284
+ try {
285
+ this.spawnCommandSync('pnpm', ['install'], {
286
+ cwd: this.destDir,
287
+ });
288
+ } catch (e) {
289
+ this._installFailed = true;
290
+ this.log('');
291
+ this.log('⚠️ 依赖安装失败,但项目文件已全部生成。');
292
+ this.logger.verbose('Install error:', e.message);
293
+ return;
294
+ }
295
+
296
+ // 依赖安装成功后,格式化生成的文件以消除风格差异
297
+ const layoutDir = path.join(this.destDir, 'apps/layout');
298
+ if (fs.existsSync(path.join(layoutDir, '.prettierrc'))) {
299
+ this.log('');
300
+ this.log('🎨 格式化生成的文件...');
301
+ try {
302
+ this.spawnCommandSync('pnpm', ['-C', 'apps/layout', 'format'], {
303
+ cwd: this.destDir,
304
+ });
305
+ } catch (e) {
306
+ this.logger.verbose('Formatting failed (non-critical):', e.message);
307
+ }
308
+ }
284
309
  }
285
310
 
286
311
  end() {
@@ -288,7 +313,20 @@ module.exports = class extends Generator {
288
313
  if (this._skipInstall) return;
289
314
 
290
315
  this.log('');
291
- this.log('✅ 项目创建成功!');
316
+
317
+ if (this._installFailed) {
318
+ this.log('⚠️ 项目文件已创建,但依赖安装未完成。');
319
+ this.log('');
320
+ this.log(' 请手动安装依赖:');
321
+ this.log('');
322
+ this.log(' pnpm install');
323
+ this.log('');
324
+ this.log(' 如果安装仍然失败,可尝试:');
325
+ this.log(' pnpm install --network-concurrency 4');
326
+ } else {
327
+ this.log('✅ 项目创建成功!');
328
+ }
329
+
292
330
  this.log('');
293
331
  this.log(' 后续步骤:');
294
332
  this.log('');
@@ -7,6 +7,7 @@
7
7
  "qiankun 微前端架构",
8
8
  "Arco Design + Tailwind CSS",
9
9
  "主题切换、国际化、认证模块",
10
- "可配置 CDN 路径前缀(支持多业务线隔离)"
10
+ "可配置 CDN 路径前缀(支持多业务线隔离)",
11
+ "Sentry 错误监控与 SourceMap 上传"
11
12
  ]
12
13
  }
@@ -20,8 +20,15 @@ docs/
20
20
  ### 2. Layout 应用文档 (`/apps/layout/docs/`)
21
21
  ```
22
22
  apps/layout/docs/
23
- ├── feature-微前端模式.md # qiankun 微前端架构
24
- └── feature-主题色切换.md # 主题系统实现
23
+ ├── feature-微前端模式.md # qiankun 微前端架构
24
+ ├── feature-路由与菜单解耦.md # PAGES/MENUS 数据源分离、双层权限
25
+ ├── feature-菜单权限控制.md # sideMenus 白名单、认证与授权分离
26
+ ├── feature-主题色切换.md # 主题系统实现
27
+ ├── feature-404页面.md # 404 页面
28
+ ├── arch-请求模块.md # HTTP 请求层模块化设计
29
+ ├── arch-日志与常量.md # Logger 工具与常量管理
30
+ ├── common-intl.md # 国际化公共包
31
+ └── utils-timezone.md # 时区工具
25
32
  ```
26
33
 
27
34
  ### 3. 其他应用文档
@@ -33,8 +40,9 @@ apps/layout/docs/
33
40
 
34
41
  ### Step 1: 确认需求涉及的模块
35
42
  - 微前端相关 → 阅读 `apps/layout/docs/feature-微前端模式.md`
43
+ - 路由/菜单/权限相关 → 阅读 `apps/layout/docs/feature-路由与菜单解耦.md` 和 `apps/layout/docs/feature-菜单权限控制.md`
36
44
  - 主题/样式相关 → 阅读 `apps/layout/docs/feature-主题色切换.md`
37
- - 请求/认证相关 → 阅读 `src/common/request/` 和 `src/common/auth/` 源码
45
+ - 请求/认证相关 → 阅读 `apps/layout/docs/arch-请求模块.md` 和 `src/common/auth/` 源码
38
46
  - 菜单相关 → 阅读 `src/common/menu/` 源码
39
47
 
40
48
  ### Step 2: 查找相关文档
@@ -54,9 +62,11 @@ find . -name "*.md" -type f | grep -v node_modules
54
62
  | 需求类型 | 必读文档 |
55
63
  |---------|---------|
56
64
  | 新建子应用 | `apps/layout/docs/feature-微前端模式.md` |
65
+ | 路由/页面配置 | `apps/layout/docs/feature-路由与菜单解耦.md` |
66
+ | 权限控制 | `apps/layout/docs/feature-菜单权限控制.md` |
57
67
  | 主题适配 | `apps/layout/docs/feature-主题色切换.md` |
58
68
  | 提交代码 | `docs/commit-message.md` |
59
- | API 请求 | `src/common/request/index.ts` 源码注释 |
69
+ | API 请求 | `apps/layout/docs/arch-请求模块.md` |
60
70
  | 认证登录 | `src/common/auth/` 目录源码 |
61
71
  | 菜单配置 | `src/common/menu/types.ts` 类型定义 |
62
72
 
@@ -63,24 +63,27 @@ apps/layout/
63
63
  const BasicLayout: React.FC = () => {
64
64
  const location = useLocation();
65
65
 
66
- // 解析路由配置
67
- const routes = useMemo(() => {
68
- const menus = getWindowMenus();
69
- return extractRoutes(menus);
66
+ // 所有页面路由(优先 PAGES,降级 MENUS)— 用于路由匹配和渲染
67
+ const allPageRoutes = useMemo(() => {
68
+ return getDynamicRoutes();
70
69
  }, []);
71
70
 
72
- // 查找当前路由配置
71
+ // 菜单路由(从 MENUS)— 用于权限交叉引用
72
+ const allMenuRoutes = useMemo(() => {
73
+ return extractRoutes(getMenus());
74
+ }, []);
75
+
76
+ // 当前路由配置(从所有页面路由中查找)
73
77
  const currentRoute = useMemo(() => {
74
- return findRouteByPath(routes, location.pathname);
75
- }, [routes, location.pathname]);
78
+ return findRouteByPath(allPageRoutes, location.pathname);
79
+ }, [allPageRoutes, location.pathname]);
76
80
 
77
81
  // 渲染页面内容
78
82
  const renderContent = () => {
79
- // 微应用类型使用 MicroAppLoader
80
83
  if (currentRoute?.loadType === 'microapp' && currentRoute.entry) {
81
- return <MicroAppLoader entry={currentRoute.entry} name={currentRoute.path} />;
84
+ const appName = getAppNameFromEntry(currentRoute.entry);
85
+ return <MicroAppLoader entry={currentRoute.entry} name={appName} />;
82
86
  }
83
- // 内部路由使用 Outlet
84
87
  return <Outlet />;
85
88
  };
86
89
 
@@ -98,28 +101,36 @@ const BasicLayout: React.FC = () => {
98
101
  };
99
102
  ```
100
103
 
101
- ### 2. 菜单系统 (common/menu/)
104
+ ### 2. 全局数据源 (common/portal-data.ts) + 菜单系统 (common/menu/)
102
105
 
103
106
  ```typescript
104
- // 获取菜单数据
105
- const menus = getWindowMenus();
107
+ // 获取页面列表 (window.__MICO_PAGES__)
108
+ const pages = getPages();
109
+
110
+ // 获取菜单树 (window.__MICO_MENUS__)
111
+ const menus = getMenus();
106
112
 
107
- // 提取路由配置
108
- const routes = extractRoutes(menus);
113
+ // 从页面列表提取动态路由(优先数据源)
114
+ const routes = getDynamicRoutes();
109
115
 
110
- // 解析菜单项
116
+ // 从菜单树提取路由(用于权限交叉引用)
117
+ const menuRoutes = extractRoutes(menus);
118
+
119
+ // 解析菜单项(用于侧边栏渲染)
111
120
  const menuItems = parseMenuItems(menus);
112
121
 
113
122
  // 查找当前路由
114
123
  const currentRoute = findRouteByPath(routes, pathname);
124
+
125
+ // 通过 pageId 查找页面(O(1))
126
+ const page = getPageById(pageId);
115
127
  ```
116
128
 
117
129
  ### 3. 动态路由 (app.tsx)
118
130
 
119
131
  ```typescript
120
132
  export function patchClientRoutes({ routes }: { routes: any[] }) {
121
- const menus = getWindowMenus();
122
- const dynamicRoutes = extractRoutes(menus);
133
+ const dynamicRoutes = getDynamicRoutes(); // 从 __MICO_PAGES__ 获取
123
134
 
124
135
  const rootRoute = routes.find((r) => r.path === '/');
125
136
  dynamicRoutes.forEach((route) => {
@@ -128,9 +139,7 @@ export function patchClientRoutes({ routes }: { routes: any[] }) {
128
139
  name: route.name,
129
140
  meta: {
130
141
  loadType: route.loadType,
131
- htmlUrl: route.htmlUrl,
132
- jsUrls: route.jsUrls,
133
- cssUrls: route.cssUrls,
142
+ entry: route.entry,
134
143
  },
135
144
  });
136
145
  });
@@ -265,8 +274,9 @@ const { collapsed } = useModel('global');
265
274
 
266
275
  ## 注意事项
267
276
 
268
- 1. **菜单数据来源**: 通过 `window.__MICO_MENUS__` 注入
269
- 2. **路由动态生成**: 在 `patchClientRoutes` 中根据菜单生成路由
270
- 3. **微应用判断**: 根据 `htmlUrl` 或 `jsUrls` 判断是否为微应用
271
- 4. **主题初始化**: `app.tsx` 中调用 `initTheme()` 避免闪烁
272
- 5. **认证共享**: 子应用使用主应用传递的 `request` 实例
277
+ 1. **数据来源**: 页面列表通过 `window.__MICO_PAGES__` 注入,菜单树通过 `window.__MICO_MENUS__` 注入
278
+ 2. **路由动态生成**: 在 `patchClientRoutes` 中优先从 `__MICO_PAGES__` 生成路由
279
+ 3. **权限交叉引用**: 菜单路由(`__MICO_MENUS__`)用于权限判断,页面路由(`__MICO_PAGES__`)用于渲染
280
+ 4. **微应用判断**: 根据 `htmlUrl` `jsUrls` 判断是否为微应用
281
+ 5. **主题初始化**: `app.tsx` 中调用 `initTheme()` 避免闪烁
282
+ 6. **认证共享**: 子应用使用主应用传递的 `request` 实例
@@ -61,15 +61,16 @@ alwaysApply: true
61
61
  - **关键文件**:
62
62
  - `src/layouts/index.tsx` - 主布局组件
63
63
  - `src/components/MicroAppLoader/` - 微应用加载器
64
- - `src/common/menu/parser.ts` - 菜单解析与路由提取
64
+ - `src/common/menu/parser.ts` - 菜单解析、页面数据提取与路由生成
65
65
  - `src/common/request/index.ts` - 统一请求封装
66
66
  - `src/hooks/useTheme.ts` - 主题管理 Hook
67
67
 
68
68
  ### 2. 微前端架构
69
- - 菜单数据通过 `window.__MICO_MENUS__` 注入
69
+ - 路由注册优先使用 `window.__MICO_PAGES__`(页面列表),无数据时降级到 `window.__MICO_MENUS__`(菜单树)
70
70
  - 根据 `htmlUrl` 或 `jsUrls` 判断是否为微应用
71
71
  - 使用 `loadMicroApp` API 动态挂载子应用
72
72
  - 子应用共享主应用的 `request` 实例
73
+ - 权限通过菜单交叉引用 + 页面级兜底的双层策略控制
73
74
 
74
75
  ### 3. 主题系统
75
76
  - 支持亮色/暗黑主题切换
@@ -123,6 +124,8 @@ Jenkins 根据环境执行 `CICD/` 下的构建脚本:
123
124
  ## 相关文档
124
125
 
125
126
  - [微前端模式](mdc:apps/layout/docs/feature-微前端模式.md)
127
+ - [路由与菜单解耦](mdc:apps/layout/docs/feature-路由与菜单解耦.md)
128
+ - [菜单权限控制](mdc:apps/layout/docs/feature-菜单权限控制.md)
126
129
  - [主题色切换](mdc:apps/layout/docs/feature-主题色切换.md)
127
130
  - [提交规范](mdc:docs/commit-message.md)
128
131
  - [部署说明](mdc:deployDesc.md)
@@ -108,8 +108,8 @@ Logger 工具在 `src/common/logger.ts`,常量定义在 `src/constants/index.t
108
108
  ### 认证模块
109
109
  认证逻辑在 `src/common/auth/`,核心文件 `auth-manager.ts` 管理 Token 存储和用户信息。SSO 登录在 `getInitialState()` 中完成,确保 UI 渲染前认证已就绪。
110
110
 
111
- ### 菜单系统
112
- 菜单解析与类型定义在 `src/common/menu/`。
111
+ ### 菜单与路由系统
112
+ 菜单解析与类型定义在 `src/common/menu/`。路由注册消费 `window.__MICO_PAGES__`(页面列表),菜单栏消费 `window.__MICO_MENUS__`(菜单树),两者解耦运作。权限通过菜单交叉引用 + 页面级兜底的双层策略控制。详见 [路由与菜单解耦](./apps/layout/docs/feature-路由与菜单解耦.md) 和 [菜单权限控制](./apps/layout/docs/feature-菜单权限控制.md)。
113
113
 
114
114
  ### 微前端
115
115
  layout 应用作为 qiankun 主应用,子应用通过 Umi 配置中的 qiankun 配置注册。详见 [微前端模式](./apps/layout/docs/feature-微前端模式.md)。
@@ -121,6 +121,8 @@ layout 应用作为 qiankun 主应用,子应用通过 Umi 配置中的 qiankun
121
121
  | [README.md](./README.md) | 项目入口、技术栈、常用命令 |
122
122
  | [提交规范](./docs/commit-message.md) | Git Commit 详细规范 |
123
123
  | [微前端模式](./apps/layout/docs/feature-微前端模式.md) | qiankun 架构、MicroAppLoader、子应用配置 |
124
+ | [路由与菜单解耦](./apps/layout/docs/feature-路由与菜单解耦.md) | PAGES/MENUS 数据源分离、双层权限控制 |
125
+ | [菜单权限控制](./apps/layout/docs/feature-菜单权限控制.md) | sideMenus 白名单、认证与授权分离 |
124
126
  | [主题色切换](./apps/layout/docs/feature-主题色切换.md) | useTheme Hook、CSS 变量系统 |
125
127
  | [请求模块架构](./apps/layout/docs/arch-请求模块.md) | HTTP 请求层模块化设计 |
126
128
  | [日志与常量](./apps/layout/docs/arch-日志与常量.md) | Logger 工具与常量管理 |
@@ -56,4 +56,6 @@ build
56
56
 
57
57
  **/tasks/*
58
58
 
59
- .pnpm-store/**
59
+ .pnpm-store/**
60
+
61
+ .worktrees/**
@@ -1,5 +1,6 @@
1
1
  registry=https://registry.npmjs.com/
2
2
  @mico-platform:registry=https://nexus-vywrajy.micoworld.net/repository/mico-base-common/
3
+ @common-web:registry=https://nexus-vywrajy.micoworld.net/repository/mico-base-common/
3
4
  package-lock=false
4
5
  //nexus-vywrajy.micoworld.net/repository/mico-base-common/:_auth=bWljby1ucG06SDR4WUROazdad1NeczltblJMTw==
5
6
 
@@ -4,6 +4,7 @@ import { defineConfig } from '@umijs/max';
4
4
 
5
5
 
6
6
  import mockMenus from '../mock/menus';
7
+ import mockPages from '../mock/pages';
7
8
 
8
9
  const config: ReturnType<typeof defineConfig> = {
9
10
  publicPath: '/',
@@ -16,18 +17,21 @@ const config: ReturnType<typeof defineConfig> = {
16
17
  {
17
18
  content: `
18
19
  window.__MICO_MENUS__ = ${JSON.stringify(mockMenus)};
20
+ window.__MICO_PAGES__ = ${JSON.stringify(mockPages)};
19
21
  window.__MICO_CONFIG__ = {
20
22
  appName: '<%= projectName %>',
23
+ title: '测试样例',
24
+ logo: '',
21
25
  apiBaseUrl: '',
22
26
  defaultPath: '',
23
27
  // 免认证路由(跳过 SSO 登录),支持 /* 前缀匹配
24
28
  // noAuthRouteList: ['/*'],
25
29
  // 免权限校验路由(跳过菜单权限检查)
26
- // noPermissionRouteList: ['/task-query/*'],
30
+ noPermissionRouteList: [],
27
31
  // 不显示布局的路由(全屏页面)
28
- // noLayoutRouteList: ['/task-query/*'],
32
+ // noLayoutRouteList: [],
29
33
  // 关闭权限控制(调试用)
30
- disableAuth: true,
34
+ disableAuth: false,
31
35
  };
32
36
  `,
33
37
  },
@@ -3,6 +3,11 @@
3
3
  import { defineConfig } from '@umijs/max';
4
4
 
5
5
  const config: ReturnType<typeof defineConfig> = {
6
+ externals: {
7
+ react: 'React',
8
+ 'react-dom': 'ReactDOM',
9
+ '@common-web/sentry': 'CommonWebSentry',
10
+ },
6
11
  define: {
7
12
  'process.env.NODE_ENV': 'development',
8
13
  'process.env.APP_ID': '<%= projectName %>',
@@ -3,6 +3,11 @@
3
3
  import { defineConfig } from '@umijs/max';
4
4
 
5
5
  const config: ReturnType<typeof defineConfig> = {
6
+ externals: {
7
+ react: 'React',
8
+ 'react-dom': 'ReactDOM',
9
+ '@common-web/sentry': 'CommonWebSentry',
10
+ },
6
11
  define: {
7
12
  'process.env.NODE_ENV': 'testing',
8
13
  'process.env.APP_ID': '<%= projectName %>',
@@ -1,6 +1,7 @@
1
1
  // https://umijs.org/config/
2
2
 
3
3
  import { defineConfig } from '@umijs/max';
4
+ import { applySentryPlugin } from '../../../scripts/apply-sentry-plugin';
4
5
  const { CDN_PUBLIC_PATH } = process.env;
5
6
 
6
7
  const PUBLIC_PATH: string = CDN_PUBLIC_PATH
@@ -8,6 +9,11 @@ const PUBLIC_PATH: string = CDN_PUBLIC_PATH
8
9
  : '/layout/';
9
10
 
10
11
  const config: ReturnType<typeof defineConfig> = {
12
+ /**
13
+ * 启用 Source Map(用于 Sentry 错误追踪)
14
+ * hidden-source-map 会生成 .map 文件但不在 JS 中添加 sourcemap 注释
15
+ */
16
+ devtool: 'hidden-source-map',
11
17
  define: {
12
18
  'process.env.NODE_ENV': 'production',
13
19
  'process.env.APP_ID': '<%= projectName %>',
@@ -20,6 +26,11 @@ const config: ReturnType<typeof defineConfig> = {
20
26
  'process.env.EXTERNAL_LOGIN_PATH':
21
27
  'https://micous-idp.cig.tencentcs.com/sso/xxxxxxx/cas',
22
28
  },
29
+ externals: {
30
+ react: 'React',
31
+ 'react-dom': 'ReactDOM',
32
+ '@common-web/sentry': 'CommonWebSentry',
33
+ },
23
34
  // 生产环境:将所有代码打包到一个文件
24
35
  extraBabelPlugins: ['babel-plugin-dynamic-import-node'],
25
36
 
@@ -29,6 +40,7 @@ const config: ReturnType<typeof defineConfig> = {
29
40
  memo.optimization.splitChunks(false);
30
41
  // 禁用 runtimeChunk
31
42
  memo.optimization.runtimeChunk(false);
43
+ applySentryPlugin({ memo, appName: 'layout' });
32
44
  return memo;
33
45
  },
34
46
  publicPath: PUBLIC_PATH,
@@ -5,11 +5,6 @@
5
5
  * @note Umi Max 会自动使用 src/layouts/index.tsx 作为全局布局,无需显式配置
6
6
  */
7
7
  export default [
8
- {
9
- path: '/user/login',
10
- component: './User/Login',
11
- name: '登录',
12
- },
13
8
  {
14
9
  path: '/',
15
10
  component: './Home',
@@ -18,8 +18,8 @@
18
18
 
19
19
  ### 核心实现
20
20
 
21
- 1. 主应用通过 `window.__MICO_MENUS__` 获取菜单配置
22
- 2. 解析菜单时根据 `htmlUrl` 或 `jsUrls` 判断是否为微应用
21
+ 1. 主应用优先通过 `window.__MICO_PAGES__` 获取页面配置,无数据时降级到 `window.__MICO_MENUS__`(详见 [路由与菜单解耦](./feature-路由与菜单解耦.md))
22
+ 2. 解析页面时根据 `htmlUrl` 或 `jsUrls` 判断是否为微应用
23
23
  3. 路由匹配时,微应用类型使用 `MicroAppLoader` 组件加载
24
24
  4. `MicroAppLoader` 使用 qiankun 的 `loadMicroApp` API 动态挂载子应用
25
25
  5. 组件卸载时自动调用 `unmount()` 清理子应用
@@ -421,6 +421,8 @@ export default function HomePage() {
421
421
 
422
422
  ## 相关文档
423
423
 
424
+ - [路由与菜单解耦](./feature-路由与菜单解耦.md) - 路由注册与菜单导航数据源分离
425
+ - [菜单权限控制](./feature-菜单权限控制.md) - sideMenus 白名单权限逻辑
424
426
  - [主题色切换](./feature-主题色切换.md) - 主题系统实现与子应用适配
425
427
  - [请求模块架构](./arch-请求模块.md) - HTTP 请求层模块化设计
426
428
  - [日志与常量](./arch-日志与常量.md) - Logger 工具与常量管理