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
@@ -9,7 +9,10 @@ const {
9
9
  collectFiles,
10
10
  transformDestPath,
11
11
  isTemplateFile,
12
- setupErrorHandlers
12
+ getPackageVersionsParallel,
13
+ setupErrorHandlers,
14
+ createLogger,
15
+ loadMicorc,
13
16
  } = require('../../lib/utils');
14
17
 
15
18
  const IGNORE_LIST = require('./ignore-list.json');
@@ -20,61 +23,98 @@ setupErrorHandlers();
20
23
  module.exports = class extends Generator {
21
24
  initializing() {
22
25
  this.projectRoot = process.cwd();
26
+ this.logger = createLogger(this);
23
27
 
24
- // 检查当前目录是否已是一个 monorepo
28
+ // 检查 dry-run 模式
29
+ this.isDryRun = this.options.dryRun || process.env.MICO_DRY_RUN === '1';
30
+
31
+ // 加载 .micorc 配置
32
+ const { config: rcConfig, configPath } = loadMicorc(this.projectRoot);
33
+ this.rcConfig = rcConfig;
34
+ if (configPath) {
35
+ this.logger.verbose('Loaded config from:', configPath);
36
+ this.logger.verbose('Config:', JSON.stringify(rcConfig, null, 2));
37
+ }
38
+
39
+ // 检查当前目录是否已是一个 monorepo(--force 跳过此检查)
25
40
  const workspaceFile = path.join(this.projectRoot, 'pnpm-workspace.yaml');
26
- if (fs.existsSync(workspaceFile)) {
41
+ if (fs.existsSync(workspaceFile) && !this.options.force) {
27
42
  console.error('');
28
43
  console.error('❌ Error: Current directory is already a monorepo.');
29
44
  console.error('');
30
45
  console.error(' A pnpm-workspace.yaml file already exists.');
31
- console.error(' Please run this command in an empty directory or specify a new project name.');
46
+ console.error(
47
+ ' Please run this command in an empty directory or specify a new project name.',
48
+ );
32
49
  console.error('');
33
50
  console.error(' Usage:');
34
51
  console.error(' mkdir my-project && cd my-project');
35
52
  console.error(' mico create micro-react');
36
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('');
37
57
  process.exit(1);
38
58
  }
39
59
  }
40
60
 
41
61
  async prompting() {
42
62
  try {
63
+ // 使用 .micorc 中的值作为默认值
64
+ const rc = this.rcConfig || {};
65
+
43
66
  this.answers = await this.prompt([
44
67
  {
45
68
  type: 'input',
46
69
  name: 'projectName',
47
70
  message: 'Project name',
48
- default: path.basename(this.projectRoot),
71
+ default: rc.projectName || path.basename(this.projectRoot),
49
72
  filter: (input) => toKebab(input),
50
73
  validate: (input) => {
51
74
  const value = toKebab(input);
52
75
  if (!value) return 'Project name is required';
53
76
  return true;
54
- }
77
+ },
55
78
  },
56
79
  {
57
80
  type: 'input',
58
81
  name: 'packageScope',
59
82
  message: 'Package scope (e.g., @my-project)',
60
- default: (answers) => `@${toKebab(answers.projectName)}`,
83
+ default: (answers) => rc.packageScope || `@${toKebab(answers.projectName)}`,
61
84
  validate: (input) => {
62
85
  if (!input) return 'Package scope is required';
63
- if (!input.startsWith('@')) return 'Package scope must start with @';
86
+ if (!input.startsWith('@'))
87
+ return 'Package scope must start with @';
64
88
  return true;
65
- }
89
+ },
90
+ },
91
+ {
92
+ type: 'input',
93
+ name: 'cdnPrefix',
94
+ message: `CDN path prefix (用于区分不同业务线的 CDN 目录)
95
+ 示例:CDN 完整路径 = https://cdn.example.com/<prefix>/<projectName>/<version>/
96
+ - 留空: https://cdn.example.com/my-project/1.0.0/
97
+ - 输入 "portal": https://cdn.example.com/portal/my-project/1.0.0/
98
+ - 输入 "admin/v2": https://cdn.example.com/admin/v2/my-project/1.0.0/
99
+ Prefix`,
100
+ default: rc.cdnPrefix || '',
101
+ filter: (input) => {
102
+ // 移除首尾斜杠,规范化路径
103
+ return input.trim().replace(/^\/+|\/+$/g, '');
104
+ },
66
105
  },
67
106
  {
68
107
  type: 'input',
69
108
  name: 'author',
70
109
  message: 'Author',
71
- default: 'Your Name <email@example.com>'
72
- }
110
+ default: rc.author || 'Your Name <email@example.com>',
111
+ },
73
112
  ]);
74
113
 
75
114
  this.projectName = toKebab(this.answers.projectName);
76
115
  this.ProjectName = toPascal(this.projectName);
77
116
  this.packageScope = this.answers.packageScope;
117
+ this.cdnPrefix = this.answers.cdnPrefix;
78
118
  this.author = this.answers.author;
79
119
  this.templateDir = this.templatePath();
80
120
  this.destDir = this.projectRoot;
@@ -87,7 +127,7 @@ module.exports = class extends Generator {
87
127
  }
88
128
  }
89
129
 
90
- writing() {
130
+ async writing() {
91
131
  try {
92
132
  if (!fs.existsSync(this.templateDir)) {
93
133
  console.error('');
@@ -97,14 +137,50 @@ module.exports = class extends Generator {
97
137
  process.exit(1);
98
138
  }
99
139
 
140
+ this.logger.verbose('Template directory:', this.templateDir);
141
+ this.logger.verbose('Destination directory:', this.destDir);
142
+
143
+ // 在 mico_cli 根目录执行 npm view,以使用该目录 .npmrc 中的 Nexus 认证
144
+ const cliRoot = path.resolve(__dirname, '../..');
145
+ this.logger.verbose('Fetching latest package versions (parallel)...');
146
+
147
+ // 并行获取版本
148
+ const versions = await getPackageVersionsParallel(
149
+ [
150
+ { name: '@mico-platform/ui', fallback: '1.0.0' },
151
+ { name: '@mico-platform/theme', fallback: '1.0.0' },
152
+ ],
153
+ 8000,
154
+ cliRoot,
155
+ );
156
+
157
+ const micoUiVer = versions['@mico-platform/ui'];
158
+ const themeVer = versions['@mico-platform/theme'];
159
+
160
+ this.logger.verbose('@mico-platform/ui version:', micoUiVer);
161
+ this.logger.verbose('@mico-platform/theme version:', themeVer);
162
+
163
+ // 构建 CDN 路径片段:如果有 prefix 则加上斜杠前缀,否则为空
164
+ const cdnPrefixPath = this.cdnPrefix ? `${this.cdnPrefix}/` : '';
165
+
100
166
  const templateData = {
101
167
  projectName: this.projectName,
102
168
  ProjectName: this.ProjectName,
103
169
  packageScope: this.packageScope,
104
- author: this.author
170
+ author: this.author,
171
+ micoUiVersion: `^${micoUiVer}`,
172
+ themeVersion: `^${themeVer}`,
173
+ cdnPrefix: this.cdnPrefix,
174
+ cdnPrefixPath, // 用于拼接路径,已包含尾部斜杠
105
175
  };
106
176
 
107
- const files = collectFiles(this.templateDir, this.templateDir, IGNORE_LIST);
177
+ this.logger.verbose('Template data:', JSON.stringify(templateData, null, 2));
178
+
179
+ const files = collectFiles(
180
+ this.templateDir,
181
+ this.templateDir,
182
+ IGNORE_LIST,
183
+ );
108
184
 
109
185
  if (files.length === 0) {
110
186
  console.error('');
@@ -114,22 +190,72 @@ module.exports = class extends Generator {
114
190
  process.exit(1);
115
191
  }
116
192
 
193
+ // Dry-run 模式:只列出文件,不实际创建
194
+ if (this.isDryRun) {
195
+ this.log('');
196
+ this.log('\x1b[33m📋 Dry run mode - no files will be created\x1b[0m');
197
+ this.log('');
198
+ this.log(` Project: ${this.projectName}`);
199
+ this.log(` Scope: ${this.packageScope}`);
200
+ this.log(` Destination: ${this.destDir}`);
201
+ this.log('');
202
+ this.log(' Would create the following files:');
203
+ this.log('');
204
+
205
+ let templateCount = 0;
206
+ let copyCount = 0;
207
+
208
+ for (const relPath of files) {
209
+ const destRelPath = transformDestPath(relPath);
210
+ const isTemplate = isTemplateFile(relPath);
211
+ const tag = isTemplate ? '\x1b[32m[tpl]\x1b[0m' : '\x1b[36m[cpy]\x1b[0m';
212
+ this.log(` ${tag} ${destRelPath}`);
213
+
214
+ if (isTemplate) {
215
+ templateCount++;
216
+ } else {
217
+ copyCount++;
218
+ }
219
+ }
220
+
221
+ this.log('');
222
+ this.log(` Total: ${files.length} files (${templateCount} templates, ${copyCount} static)`);
223
+ this.log('');
224
+ this.log(' Run without --dry-run to actually create these files.');
225
+ this.log('');
226
+
227
+ // 设置标记以跳过后续阶段
228
+ this._skipInstall = true;
229
+ return;
230
+ }
231
+
117
232
  this.log('');
118
233
  this.log(`📦 Creating project: ${this.projectName}`);
119
234
  this.log(` Scope: ${this.packageScope}`);
120
235
  this.log('');
121
236
 
237
+ this.logger.verbose(`Processing ${files.length} files...`);
238
+
239
+ let templateCount = 0;
240
+ let copyCount = 0;
241
+
122
242
  for (const relPath of files) {
123
243
  const srcPath = path.join(this.templateDir, relPath);
124
244
  const destRelPath = transformDestPath(relPath);
125
245
  const destPath = path.join(this.destDir, destRelPath);
126
246
 
127
247
  if (isTemplateFile(relPath)) {
248
+ this.logger.file('template', destRelPath);
128
249
  this.fs.copyTpl(srcPath, destPath, templateData);
250
+ templateCount++;
129
251
  } else {
252
+ this.logger.file('copy', destRelPath);
130
253
  this.fs.copy(srcPath, destPath);
254
+ copyCount++;
131
255
  }
132
256
  }
257
+
258
+ this.logger.verbose(`Processed: ${templateCount} templates, ${copyCount} copied`);
133
259
  } catch (error) {
134
260
  console.error('');
135
261
  console.error('❌ Error during file generation:');
@@ -139,15 +265,71 @@ module.exports = class extends Generator {
139
265
  }
140
266
  }
141
267
 
268
+ install() {
269
+ // 跳过 dry-run 模式
270
+ if (this._skipInstall) return;
271
+
272
+ // 检查并初始化 git
273
+ const gitDir = path.join(this.destDir, '.git');
274
+ if (!fs.existsSync(gitDir)) {
275
+ this.log('');
276
+ this.log('🔧 初始化 Git 仓库...');
277
+ this.spawnCommandSync('git', ['init'], {
278
+ cwd: this.destDir,
279
+ });
280
+ }
281
+
282
+ this.log('');
283
+ this.log('📦 正在安装依赖...');
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
+ }
309
+ }
310
+
142
311
  end() {
312
+ // 跳过 dry-run 模式
313
+ if (this._skipInstall) return;
314
+
143
315
  this.log('');
144
- 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
+
145
330
  this.log('');
146
331
  this.log(' 后续步骤:');
147
332
  this.log('');
148
- this.log(' # 安装依赖');
149
- this.log(' pnpm install');
150
- this.log('');
151
333
  this.log(' # 启动开发服务器');
152
334
  this.log(' pnpm dev');
153
335
  this.log('');
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "micro-react",
3
+ "description": "创建基于 qiankun 的微前端 Monorepo 项目",
4
+ "usage": "mkdir my-project && cd my-project && mico create micro-react",
5
+ "features": [
6
+ "Turborepo + pnpm Workspace",
7
+ "qiankun 微前端架构",
8
+ "Arco Design + Tailwind CSS",
9
+ "主题切换、国际化、认证模块",
10
+ "可配置 CDN 路径前缀(支持多业务线隔离)",
11
+ "Sentry 错误监控与 SourceMap 上传"
12
+ ]
13
+ }
@@ -2,5 +2,6 @@ module.exports = {
2
2
  extends: ['@commitlint/config-conventional'],
3
3
  rules: {
4
4
  'header-max-length': [0, 'always', 10000],
5
+ 'body-max-line-length': [0, 'always', Infinity],
5
6
  },
6
7
  };
@@ -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
 
@@ -21,7 +21,7 @@ globs: ["CICD/**", "deployDesc.md"]
21
21
  │ ↓ │
22
22
  │ ┌─────────────────────────────────────────────────────────────┐│
23
23
  │ │ 构建产物:dist/{app}/ ││
24
- │ │ 上传 CDN:cdn-portal[-env].micoplatform.com/<%= projectName %>/ ││
24
+ │ │ 上传 CDN:cdn-portal[-env].micoplatform.com/<%= cdnPrefixPath %><%= projectName %>/ ││
25
25
  │ └─────────────────────────────────────────────────────────────┘│
26
26
  └─────────────────────────────────────────────────────────────────┘
27
27
  ```
@@ -51,7 +51,7 @@ pnpm install
51
51
  VERSION=$(node -p "require('./package.json').version")
52
52
 
53
53
  # 3. 设置 CDN 路径
54
- export CDN_PUBLIC_PATH="https://cdn-portal[-env].micoplatform.com/<%= projectName %>/${VERSION}/"
54
+ export CDN_PUBLIC_PATH="https://cdn-portal[-env].micoplatform.com/<%= cdnPrefixPath %><%= projectName %>/${VERSION}/"
55
55
 
56
56
  # 4. 执行构建
57
57
  pnpm run build:[environment]
@@ -78,12 +78,14 @@ echo "VERSION=$VERSION" > .env_x_<%= projectName %>
78
78
  ### CDN 路径结构
79
79
  ```
80
80
  cdn-portal.micoplatform.com/
81
- └── <%= projectName %>/
82
- └── {version}/
83
- └── dist/
84
- ├── layout/ # 主应用
85
- ├── homepage/ # 子应用
86
- └── ...
81
+ <% if (cdnPrefix) { %>└── <%= cdnPrefix %>/
82
+ └── <%= projectName %>/
83
+ <% } else { %>└── <%= projectName %>/
84
+ <% } %> └── {version}/
85
+ └── dist/
86
+ ├── layout/ # 主应用
87
+ ├── homepage/ # 子应用
88
+ └── ...
87
89
  ```
88
90
 
89
91
  ## 环境变量
@@ -168,7 +168,7 @@ import React, { useState, useEffect } from 'react';
168
168
  import { useLocation } from '@umijs/max';
169
169
 
170
170
  // 2. 第三方库
171
- import { Button, Modal } from '@arco-design/web-react';
171
+ import { Button, Modal } from '@mico-platform/ui';
172
172
  import dayjs from 'dayjs';
173
173
 
174
174
  // 3. 项目内部模块(使用 @ 别名)
@@ -179,8 +179,7 @@ document.body.setAttribute('data-theme', 'dark');
179
179
  ### 文件位置
180
180
  ```
181
181
  apps/layout/mock/
182
- ├── menus.json # 菜单数据
183
- ├── menus.ts # 菜单数据处理
182
+ ├── menus.ts # 菜单 Mock 数据(带类型)
184
183
  └── user.mock.ts # 用户相关 Mock API
185
184
  ```
186
185
 
@@ -274,7 +273,7 @@ sh CICD/start_prod.sh
274
273
 
275
274
  构建产物上传到 CDN:
276
275
  ```
277
- cdn-portal[-env].micoplatform.com/<%= projectName %>/{version}/dist/{app}/
276
+ cdn-portal[-env].micoplatform.com/<%= cdnPrefixPath %><%= projectName %>/{version}/dist/{app}/
278
277
  ```
279
278
 
280
279
  - `version`:`package.json` 的 version 字段
@@ -290,6 +289,6 @@ cdn-portal[-env].micoplatform.com/<%= projectName %>/{version}/dist/{app}/
290
289
  ## 相关链接
291
290
 
292
291
  - [UmiJS 文档](https://umijs.org/)
293
- - [Arco Design](https://arco.design/)
292
+ - [@mico-platform/ui](hhttps://mico-ui.micoportal-test.com/react/docs/start)
294
293
  - [qiankun 文档](https://qiankun.umijs.org/)
295
294
  - [Turborepo 文档](https://turbo.build/repo)
@@ -52,10 +52,7 @@ apps/layout/
52
52
  ├── services/ # API 服务
53
53
  ├── models/ # Umi Model
54
54
  ├── locales/ # 国际化
55
- └── styles/ # 主题样式
56
- ├── themes/ # 主题变量
57
- ├── variables.less # Less 变量
58
- └── arco-override.less # Arco 覆盖
55
+ └── styles/ # 主题样式(变量来自 @mico-platform/theme)
59
56
  ```
60
57
 
61
58
  ## 核心模块
@@ -66,24 +63,27 @@ apps/layout/
66
63
  const BasicLayout: React.FC = () => {
67
64
  const location = useLocation();
68
65
 
69
- // 解析路由配置
70
- const routes = useMemo(() => {
71
- const menus = getWindowMenus();
72
- return extractRoutes(menus);
66
+ // 所有页面路由(优先 PAGES,降级 MENUS)— 用于路由匹配和渲染
67
+ const allPageRoutes = useMemo(() => {
68
+ return getDynamicRoutes();
73
69
  }, []);
74
70
 
75
- // 查找当前路由配置
71
+ // 菜单路由(从 MENUS)— 用于权限交叉引用
72
+ const allMenuRoutes = useMemo(() => {
73
+ return extractRoutes(getMenus());
74
+ }, []);
75
+
76
+ // 当前路由配置(从所有页面路由中查找)
76
77
  const currentRoute = useMemo(() => {
77
- return findRouteByPath(routes, location.pathname);
78
- }, [routes, location.pathname]);
78
+ return findRouteByPath(allPageRoutes, location.pathname);
79
+ }, [allPageRoutes, location.pathname]);
79
80
 
80
81
  // 渲染页面内容
81
82
  const renderContent = () => {
82
- // 微应用类型使用 MicroAppLoader
83
83
  if (currentRoute?.loadType === 'microapp' && currentRoute.entry) {
84
- return <MicroAppLoader entry={currentRoute.entry} name={currentRoute.path} />;
84
+ const appName = getAppNameFromEntry(currentRoute.entry);
85
+ return <MicroAppLoader entry={currentRoute.entry} name={appName} />;
85
86
  }
86
- // 内部路由使用 Outlet
87
87
  return <Outlet />;
88
88
  };
89
89
 
@@ -101,28 +101,36 @@ const BasicLayout: React.FC = () => {
101
101
  };
102
102
  ```
103
103
 
104
- ### 2. 菜单系统 (common/menu/)
104
+ ### 2. 全局数据源 (common/portal-data.ts) + 菜单系统 (common/menu/)
105
105
 
106
106
  ```typescript
107
- // 获取菜单数据
108
- const menus = getWindowMenus();
107
+ // 获取页面列表 (window.__MICO_PAGES__)
108
+ const pages = getPages();
109
+
110
+ // 获取菜单树 (window.__MICO_MENUS__)
111
+ const menus = getMenus();
109
112
 
110
- // 提取路由配置
111
- const routes = extractRoutes(menus);
113
+ // 从页面列表提取动态路由(优先数据源)
114
+ const routes = getDynamicRoutes();
112
115
 
113
- // 解析菜单项
116
+ // 从菜单树提取路由(用于权限交叉引用)
117
+ const menuRoutes = extractRoutes(menus);
118
+
119
+ // 解析菜单项(用于侧边栏渲染)
114
120
  const menuItems = parseMenuItems(menus);
115
121
 
116
122
  // 查找当前路由
117
123
  const currentRoute = findRouteByPath(routes, pathname);
124
+
125
+ // 通过 pageId 查找页面(O(1))
126
+ const page = getPageById(pageId);
118
127
  ```
119
128
 
120
129
  ### 3. 动态路由 (app.tsx)
121
130
 
122
131
  ```typescript
123
132
  export function patchClientRoutes({ routes }: { routes: any[] }) {
124
- const menus = getWindowMenus();
125
- const dynamicRoutes = extractRoutes(menus);
133
+ const dynamicRoutes = getDynamicRoutes(); // 从 __MICO_PAGES__ 获取
126
134
 
127
135
  const rootRoute = routes.find((r) => r.path === '/');
128
136
  dynamicRoutes.forEach((route) => {
@@ -131,9 +139,7 @@ export function patchClientRoutes({ routes }: { routes: any[] }) {
131
139
  name: route.name,
132
140
  meta: {
133
141
  loadType: route.loadType,
134
- htmlUrl: route.htmlUrl,
135
- jsUrls: route.jsUrls,
136
- cssUrls: route.cssUrls,
142
+ entry: route.entry,
137
143
  },
138
144
  });
139
145
  });
@@ -206,7 +212,7 @@ const { isAuthenticated, user, logout } = useAuth();
206
212
  ### 主题变量引入
207
213
  ```less
208
214
  // 在组件样式中使用
209
- @import '<%= packageScope %>/shared-styles/variables-only';
215
+ @import '@mico-platform/theme/variables';
210
216
 
211
217
  .my-component {
212
218
  background: @color-fill-1;
@@ -268,8 +274,9 @@ const { collapsed } = useModel('global');
268
274
 
269
275
  ## 注意事项
270
276
 
271
- 1. **菜单数据来源**: 通过 `window.__MICO_MENUS__` 注入
272
- 2. **路由动态生成**: 在 `patchClientRoutes` 中根据菜单生成路由
273
- 3. **微应用判断**: 根据 `htmlUrl` 或 `jsUrls` 判断是否为微应用
274
- 4. **主题初始化**: `app.tsx` 中调用 `initTheme()` 避免闪烁
275
- 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` 实例
@@ -16,7 +16,7 @@ alwaysApply: true
16
16
  | **Monorepo** | Turborepo + pnpm Workspace |
17
17
  | **前端框架** | UmiJS 4 (@umijs/max)、React 18、TypeScript |
18
18
  | **微前端** | qiankun |
19
- | **UI 组件** | Arco Design Web |
19
+ | **UI 组件** | @mico-platform/ui |
20
20
  | **样式方案** | Tailwind CSS + Less + CSS Variables |
21
21
  | **代码规范** | ESLint、Stylelint、Husky、Commitlint |
22
22
 
@@ -61,20 +61,21 @@ 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
  - 支持亮色/暗黑主题切换
76
77
  - 使用 CSS Variables 实现运行时动态切换
77
- - `arco-theme` 控制 Arco Design 组件
78
+ - `arco-theme` 控制 @mico-platform/ui 组件
78
79
  - `data-theme` 控制自定义样式
79
80
 
80
81
  ## 常用命令
@@ -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)