generator-mico-cli 0.1.29 → 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 (160) 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 +33 -17
  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 +10 -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/arch-/350/257/267/346/261/202/346/250/241/345/235/227.md +1 -1
  34. package/generators/micro-react/templates/apps/layout/docs/common-intl.md +372 -0
  35. 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
  36. package/generators/micro-react/templates/apps/layout/docs/feature-404/351/241/265/351/235/242.md +103 -0
  37. 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
  38. 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
  39. 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 +420 -0
  40. 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
  41. 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
  42. package/generators/micro-react/templates/apps/layout/docs/utils-timezone.md +324 -0
  43. package/generators/micro-react/templates/apps/layout/mock/api.mock.ts +81 -61
  44. package/generators/micro-react/templates/apps/layout/mock/menus.ts +114 -4
  45. package/generators/micro-react/templates/apps/layout/mock/pages.ts +86 -0
  46. package/generators/micro-react/templates/apps/layout/package.json +7 -4
  47. package/generators/micro-react/templates/apps/layout/src/app.tsx +122 -83
  48. package/generators/micro-react/templates/apps/layout/src/common/auth/index.ts +3 -0
  49. package/generators/micro-react/templates/apps/layout/src/common/helpers.ts +177 -0
  50. package/generators/micro-react/templates/apps/layout/src/common/locale.ts +22 -17
  51. package/generators/micro-react/templates/apps/layout/src/common/menu/parser.ts +283 -28
  52. package/generators/micro-react/templates/apps/layout/src/common/menu/types.ts +69 -5
  53. package/generators/micro-react/templates/apps/layout/src/common/micro/index.ts +34 -0
  54. package/generators/micro-react/templates/apps/layout/src/common/micro-prefetch.ts +109 -0
  55. package/generators/micro-react/templates/apps/layout/src/common/portal-data.ts +45 -0
  56. package/generators/micro-react/templates/apps/layout/src/common/request/config.ts +72 -10
  57. package/generators/micro-react/templates/apps/layout/src/common/request/index.ts +2 -2
  58. package/generators/micro-react/templates/apps/layout/src/common/request/interceptors.ts +31 -3
  59. package/generators/micro-react/templates/apps/layout/src/common/request/sso.ts +29 -11
  60. package/generators/micro-react/templates/apps/layout/src/common/request/url-resolver.ts +23 -8
  61. package/generators/micro-react/templates/apps/layout/src/common/route-guard.ts +345 -0
  62. package/generators/micro-react/templates/apps/layout/src/common/theme.ts +2 -4
  63. package/generators/micro-react/templates/apps/layout/src/common/upload/oss.ts +3 -4
  64. package/generators/micro-react/templates/apps/layout/src/common/upload/types.ts +1 -1
  65. package/generators/micro-react/templates/apps/layout/src/common/uploadFiles.ts +1 -1
  66. package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.less +8 -3
  67. package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.tsx +25 -8
  68. package/generators/micro-react/templates/apps/layout/src/components/HeaderDropdown/index.tsx +20 -0
  69. package/generators/micro-react/templates/apps/layout/src/components/IconFont/index.tsx +5 -6
  70. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.less +21 -6
  71. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +83 -107
  72. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/micro-app-manager.ts +569 -0
  73. package/generators/micro-react/templates/apps/layout/src/components/RightContent/AvatarDropdown.tsx +383 -0
  74. package/generators/micro-react/templates/apps/layout/src/components/RightContent/avatar-dropdown.less +35 -0
  75. package/generators/micro-react/templates/apps/layout/src/components/RightContent/index.ts +2 -0
  76. package/generators/micro-react/templates/apps/layout/src/constants/index.ts +170 -6
  77. package/generators/micro-react/templates/apps/layout/src/global.less +19 -6
  78. package/generators/micro-react/templates/apps/layout/src/hooks/useMenu.ts +3 -2
  79. package/generators/micro-react/templates/apps/layout/src/hooks/useRoutePermissionRefresh.ts +72 -0
  80. package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.less +3 -1
  81. package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.tsx +10 -55
  82. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +34 -4
  83. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +33 -9
  84. package/generators/micro-react/templates/apps/layout/src/layouts/index.less +84 -13
  85. package/generators/micro-react/templates/apps/layout/src/layouts/index.tsx +178 -47
  86. package/generators/micro-react/templates/apps/layout/src/locales/en-US.ts +12 -0
  87. package/generators/micro-react/templates/apps/layout/src/locales/zh-CN.ts +12 -0
  88. package/generators/micro-react/templates/apps/layout/src/pages/403/index.tsx +34 -0
  89. package/generators/micro-react/templates/apps/layout/src/pages/404/index.tsx +78 -0
  90. package/generators/micro-react/templates/apps/layout/src/pages/Home/index.less +3 -0
  91. package/generators/micro-react/templates/apps/layout/src/pages/Home/index.tsx +7 -1
  92. package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.less +1 -1
  93. package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.tsx +9 -5
  94. package/generators/micro-react/templates/apps/layout/src/requestErrorConfig.ts +1 -1
  95. package/generators/micro-react/templates/apps/layout/src/services/config/index.ts +63 -0
  96. package/generators/micro-react/templates/apps/layout/src/services/config/type.ts +30 -0
  97. package/generators/micro-react/templates/apps/layout/src/services/user.ts +29 -2
  98. package/generators/micro-react/templates/apps/layout/tailwind.config.js +3 -0
  99. package/generators/micro-react/templates/deployDesc.md +3 -3
  100. package/generators/micro-react/templates/dev.preset.json +14 -0
  101. package/generators/micro-react/templates/docs/dev-preset.md +130 -0
  102. package/generators/micro-react/templates/package.json +21 -6
  103. package/generators/micro-react/templates/packages/common-intl/README.md +427 -0
  104. package/generators/micro-react/templates/packages/common-intl/package.json +34 -0
  105. package/generators/micro-react/templates/packages/common-intl/src/index.ts +7 -0
  106. package/generators/micro-react/templates/packages/common-intl/src/indexedDBUtils.ts +51 -0
  107. package/generators/micro-react/templates/packages/common-intl/src/intl.ts +50 -0
  108. package/generators/micro-react/templates/packages/common-intl/src/utils.ts +482 -0
  109. package/generators/micro-react/templates/packages/common-intl/tsconfig.json +22 -0
  110. package/generators/micro-react/templates/packages/common-intl/vite.config.ts +25 -0
  111. package/generators/micro-react/templates/scripts/apply-sentry-plugin.ts +45 -0
  112. package/generators/micro-react/templates/scripts/collect-dist.js +10 -0
  113. package/generators/micro-react/templates/scripts/dev-preset.js +265 -0
  114. package/generators/micro-react/templates/scripts/dev-preset.schema.json +39 -0
  115. package/generators/micro-react/templates/turbo.json +4 -1
  116. package/generators/subapp-react/index.js +326 -40
  117. package/generators/subapp-react/meta.json +10 -0
  118. package/generators/subapp-react/templates/homepage/.env +2 -1
  119. package/generators/subapp-react/templates/homepage/README.md +3 -3
  120. package/generators/subapp-react/templates/homepage/config/config.dev.ts +14 -7
  121. package/generators/subapp-react/templates/homepage/config/config.prod.development.ts +16 -5
  122. package/generators/subapp-react/templates/homepage/config/config.prod.testing.ts +16 -5
  123. package/generators/subapp-react/templates/homepage/config/config.prod.ts +14 -5
  124. package/generators/subapp-react/templates/homepage/config/config.ts +27 -0
  125. package/generators/subapp-react/templates/homepage/config/routes.ts +2 -2
  126. package/generators/subapp-react/templates/homepage/mock/api.mock.ts +2 -2
  127. package/generators/subapp-react/templates/homepage/package.json +7 -4
  128. package/generators/subapp-react/templates/homepage/src/app.tsx +18 -27
  129. package/generators/subapp-react/templates/homepage/src/common/request.ts +29 -2
  130. package/generators/subapp-react/templates/homepage/src/global.less +6 -5
  131. package/generators/subapp-react/templates/homepage/src/pages/index.less +3 -3
  132. package/generators/subapp-react/templates/homepage/src/pages/index.tsx +99 -60
  133. package/generators/subapp-react/templates/homepage/src/styles/theme.less +1 -1
  134. package/generators/subapp-umd/ignore-list.json +5 -0
  135. package/generators/subapp-umd/index.js +309 -0
  136. package/generators/subapp-umd/meta.json +11 -0
  137. package/generators/subapp-umd/templates/README.md +94 -0
  138. package/generators/subapp-umd/templates/package.json +35 -0
  139. package/generators/subapp-umd/templates/public/index.html +34 -0
  140. package/generators/subapp-umd/templates/src/App.less +15 -0
  141. package/generators/subapp-umd/templates/src/App.tsx +13 -0
  142. package/generators/subapp-umd/templates/src/index.ts +2 -0
  143. package/generators/subapp-umd/templates/tsconfig.json +27 -0
  144. package/generators/subapp-umd/templates/webpack.config.js +70 -0
  145. package/lib/utils.js +332 -2
  146. package/package.json +15 -2
  147. package/generators/micro-react/templates/apps/layout/mock/menus.json +0 -100
  148. package/generators/micro-react/templates/apps/layout/src/common/constants.ts +0 -38
  149. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/container-manager.ts +0 -202
  150. package/generators/micro-react/templates/packages/shared-styles/README.md +0 -124
  151. package/generators/micro-react/templates/packages/shared-styles/arco-design-mobile-override.less +0 -91
  152. package/generators/micro-react/templates/packages/shared-styles/arco-override.less +0 -119
  153. package/generators/micro-react/templates/packages/shared-styles/index.d.ts +0 -44
  154. package/generators/micro-react/templates/packages/shared-styles/index.less +0 -13
  155. package/generators/micro-react/templates/packages/shared-styles/package.json +0 -30
  156. package/generators/micro-react/templates/packages/shared-styles/theme-inject.less +0 -10
  157. package/generators/micro-react/templates/packages/shared-styles/themes/dark/custom-var.less +0 -290
  158. package/generators/micro-react/templates/packages/shared-styles/themes/normal/custom-var.less +0 -269
  159. package/generators/micro-react/templates/packages/shared-styles/variables-only.less +0 -433
  160. package/generators/micro-react/templates/packages/shared-styles/variables.less +0 -452
@@ -9,7 +9,11 @@ const {
9
9
  collectFiles,
10
10
  transformDestPath,
11
11
  isTemplateFile,
12
- setupErrorHandlers
12
+ getPackageVersionsParallel,
13
+ detectPackageScope,
14
+ setupErrorHandlers,
15
+ createLogger,
16
+ loadMicorc,
13
17
  } = require('../../lib/utils');
14
18
 
15
19
  const IGNORE_LIST = require('./ignore-list.json');
@@ -20,6 +24,19 @@ setupErrorHandlers();
20
24
  module.exports = class extends Generator {
21
25
  initializing() {
22
26
  this.monorepoRoot = process.cwd();
27
+ this.logger = createLogger(this);
28
+
29
+ // 检查 dry-run 模式
30
+ this.isDryRun = this.options.dryRun || process.env.MICO_DRY_RUN === '1';
31
+
32
+ // 加载 .micorc 配置
33
+ const { config: rcConfig, configPath } = loadMicorc(this.monorepoRoot);
34
+ this.rcConfig = rcConfig;
35
+ if (configPath) {
36
+ this.logger.verbose('Loaded config from:', configPath);
37
+ this.logger.verbose('Config:', JSON.stringify(rcConfig, null, 2));
38
+ }
39
+
23
40
  const appsDir = path.join(this.monorepoRoot, 'apps');
24
41
  const workspaceFile = path.join(this.monorepoRoot, 'pnpm-workspace.yaml');
25
42
 
@@ -45,37 +62,6 @@ module.exports = class extends Generator {
45
62
  }
46
63
  }
47
64
 
48
- _detectPackageScope() {
49
- // 尝试从 packages/shared-styles/package.json 读取
50
- const sharedStylesPath = path.join(this.monorepoRoot, 'packages/shared-styles/package.json');
51
- if (fs.existsSync(sharedStylesPath)) {
52
- try {
53
- const pkg = JSON.parse(fs.readFileSync(sharedStylesPath, 'utf-8'));
54
- if (pkg.name && pkg.name.startsWith('@')) {
55
- const match = pkg.name.match(/^(@[^/]+)\//);
56
- if (match) return match[1];
57
- }
58
- } catch (e) {
59
- // 忽略解析错误
60
- }
61
- }
62
-
63
- // 尝试从根 package.json 读取
64
- const rootPkgPath = path.join(this.monorepoRoot, 'package.json');
65
- if (fs.existsSync(rootPkgPath)) {
66
- try {
67
- const pkg = JSON.parse(fs.readFileSync(rootPkgPath, 'utf-8'));
68
- if (pkg.name) {
69
- return `@${pkg.name}`;
70
- }
71
- } catch (e) {
72
- // 忽略解析错误
73
- }
74
- }
75
-
76
- return null;
77
- }
78
-
79
65
  async prompting() {
80
66
  try {
81
67
  if (!this.monorepoRoot) {
@@ -85,14 +71,15 @@ module.exports = class extends Generator {
85
71
  process.exit(1);
86
72
  }
87
73
 
88
- const detectedScope = this._detectPackageScope();
74
+ const detectedScope = detectPackageScope(this.monorepoRoot);
75
+ const rc = this.rcConfig || {};
89
76
 
90
77
  this.answers = await this.prompt([
91
78
  {
92
79
  type: 'input',
93
80
  name: 'appName',
94
81
  message: 'Sub app name',
95
- default: 'subapp',
82
+ default: rc.defaultSubappName || 'subapp',
96
83
  filter: (input) => toKebab(input),
97
84
  validate: (input) => {
98
85
  const value = toKebab(input);
@@ -108,18 +95,32 @@ module.exports = class extends Generator {
108
95
  type: 'input',
109
96
  name: 'packageScope',
110
97
  message: 'Package scope',
111
- default: detectedScope || '@my-project',
98
+ default: rc.packageScope || detectedScope || '@my-project',
112
99
  validate: (input) => {
113
100
  if (!input) return 'Package scope is required';
114
101
  if (!input.startsWith('@')) return 'Package scope must start with @';
115
102
  return true;
116
103
  }
104
+ },
105
+ {
106
+ type: 'input',
107
+ name: 'devPort',
108
+ message: 'Dev server port',
109
+ default: rc.devPort || '8010',
110
+ validate: (input) => {
111
+ const port = Number(input);
112
+ if (!Number.isInteger(port) || port < 1024 || port > 65535) {
113
+ return 'Port must be an integer between 1024 and 65535';
114
+ }
115
+ return true;
116
+ }
117
117
  }
118
118
  ]);
119
119
 
120
120
  this.appName = toKebab(this.answers.appName);
121
121
  this.appNamePascal = toPascal(this.appName);
122
122
  this.packageScope = this.answers.packageScope;
123
+ this.devPort = this.answers.devPort;
123
124
  this.templateDir = this.templatePath('homepage');
124
125
  this.destDir = path.join(this.monorepoRoot, 'apps', this.appName);
125
126
  } catch (error) {
@@ -131,7 +132,7 @@ module.exports = class extends Generator {
131
132
  }
132
133
  }
133
134
 
134
- writing() {
135
+ async writing() {
135
136
  try {
136
137
  if (!fs.existsSync(this.templateDir)) {
137
138
  console.error('');
@@ -141,12 +142,41 @@ module.exports = class extends Generator {
141
142
  process.exit(1);
142
143
  }
143
144
 
145
+ this.logger.verbose('Template directory:', this.templateDir);
146
+ this.logger.verbose('Destination directory:', this.destDir);
147
+
148
+ // 在 mico_cli 根目录执行 npm view,以使用该目录 .npmrc 中的 Nexus 认证
149
+ const cliRoot = path.resolve(__dirname, '../..');
150
+ this.logger.verbose('Fetching latest package versions (parallel)...');
151
+
152
+ // 并行获取版本
153
+ const versions = await getPackageVersionsParallel(
154
+ [
155
+ { name: '@mico-platform/ui', fallback: '1.0.0' },
156
+ { name: '@mico-platform/theme', fallback: '1.0.0' },
157
+ ],
158
+ 8000,
159
+ cliRoot,
160
+ );
161
+
162
+ const micoUiVer = versions['@mico-platform/ui'];
163
+ const themeVer = versions['@mico-platform/theme'];
164
+
165
+ this.logger.verbose('@mico-platform/ui version:', micoUiVer);
166
+ this.logger.verbose('@mico-platform/theme version:', themeVer);
167
+
144
168
  const templateData = {
145
169
  appName: this.appName,
146
170
  AppName: this.appNamePascal,
147
- packageScope: this.packageScope
171
+ packageScope: this.packageScope,
172
+ devPort: this.devPort,
173
+ micoUiVersion: `^${micoUiVer}`,
174
+ themeVersion: `^${themeVer}`,
175
+ micoUiVersionExact: micoUiVer
148
176
  };
149
177
 
178
+ this.logger.verbose('Template data:', JSON.stringify(templateData, null, 2));
179
+
150
180
  const files = collectFiles(this.templateDir, this.templateDir, IGNORE_LIST);
151
181
 
152
182
  if (files.length === 0) {
@@ -157,17 +187,77 @@ module.exports = class extends Generator {
157
187
  process.exit(1);
158
188
  }
159
189
 
190
+ // Dry-run 模式:只列出文件,不实际创建
191
+ if (this.isDryRun) {
192
+ this.log('');
193
+ this.log('\x1b[33m📋 Dry run mode - no files will be created\x1b[0m');
194
+ this.log('');
195
+ this.log(` Sub-app: ${this.appName}`);
196
+ this.log(` Scope: ${this.packageScope}`);
197
+ this.log(` Destination: apps/${this.appName}`);
198
+ this.log('');
199
+ this.log(' Would create the following files:');
200
+ this.log('');
201
+
202
+ let templateCount = 0;
203
+ let copyCount = 0;
204
+
205
+ for (const relPath of files) {
206
+ const destRelPath = transformDestPath(relPath);
207
+ const isTemplate = isTemplateFile(relPath) || path.basename(relPath) === '.env';
208
+ const tag = isTemplate ? '\x1b[32m[tpl]\x1b[0m' : '\x1b[36m[cpy]\x1b[0m';
209
+ this.log(` ${tag} apps/${this.appName}/${destRelPath}`);
210
+
211
+ if (isTemplate) {
212
+ templateCount++;
213
+ } else {
214
+ copyCount++;
215
+ }
216
+ }
217
+
218
+ this.log('');
219
+ this.log(` Total: ${files.length} files (${templateCount} templates, ${copyCount} static)`);
220
+ this.log('');
221
+ this.log(' Run without --dry-run to actually create these files.');
222
+ this.log('');
223
+
224
+ // 设置标记以跳过后续阶段
225
+ this._skipInstall = true;
226
+ return;
227
+ }
228
+
229
+ this.log('');
230
+ this.log(`📦 Creating sub-app: ${this.appName}`);
231
+ this.log(` Destination: apps/${this.appName}`);
232
+ this.log('');
233
+
234
+ this.logger.verbose(`Processing ${files.length} files...`);
235
+
236
+ let templateCount = 0;
237
+ let copyCount = 0;
238
+
160
239
  for (const relPath of files) {
161
240
  const srcPath = path.join(this.templateDir, relPath);
162
241
  const destRelPath = transformDestPath(relPath);
163
242
  const destPath = path.join(this.destDir, destRelPath);
164
243
 
165
- if (isTemplateFile(relPath)) {
244
+ const isEnvFile = path.basename(relPath) === '.env';
245
+ if (isTemplateFile(relPath) || isEnvFile) {
246
+ this.logger.file('template', destRelPath);
166
247
  this.fs.copyTpl(srcPath, destPath, templateData);
248
+ templateCount++;
167
249
  } else {
250
+ this.logger.file('copy', destRelPath);
168
251
  this.fs.copy(srcPath, destPath);
252
+ copyCount++;
169
253
  }
170
254
  }
255
+
256
+ this.logger.verbose(`Processed: ${templateCount} templates, ${copyCount} copied`);
257
+
258
+ this._updateDevPreset();
259
+ this._updateMockPages();
260
+ this._updateConfigDev();
171
261
  } catch (error) {
172
262
  console.error('');
173
263
  console.error('❌ Error during file generation:');
@@ -177,12 +267,208 @@ module.exports = class extends Generator {
177
267
  }
178
268
  }
179
269
 
270
+ _updateDevPreset() {
271
+ const presetPath = path.join(this.monorepoRoot, 'dev.preset.json');
272
+ if (!fs.existsSync(presetPath)) {
273
+ this.logger.verbose('dev.preset.json not found, skipping preset update');
274
+ return;
275
+ }
276
+
277
+ try {
278
+ const preset = JSON.parse(fs.readFileSync(presetPath, 'utf-8'));
279
+ const fullApps = preset.presets?.full?.apps;
280
+
281
+ if (!Array.isArray(fullApps)) {
282
+ this.logger.verbose('dev.preset.json has no full.apps array, skipping');
283
+ return;
284
+ }
285
+
286
+ if (fullApps.includes(this.appName)) {
287
+ this.logger.verbose(`"${this.appName}" already in full preset, skipping`);
288
+ return;
289
+ }
290
+
291
+ fullApps.push(this.appName);
292
+ fs.writeFileSync(presetPath, `${JSON.stringify(preset, null, 2)}\n`, 'utf-8');
293
+
294
+ this.log(` 📝 已将 "${this.appName}" 添加到 dev.preset.json 的 full 预设中`);
295
+ } catch (e) {
296
+ console.warn(` ⚠️ 更新 dev.preset.json 失败: ${e.message}`);
297
+ }
298
+ }
299
+
300
+ _updateMockPages() {
301
+ const pagesPath = path.join(this.monorepoRoot, 'apps/layout/mock/pages.ts');
302
+ if (!fs.existsSync(pagesPath)) {
303
+ this.logger.verbose('apps/layout/mock/pages.ts not found, skipping');
304
+ return;
305
+ }
306
+
307
+ try {
308
+ const content = fs.readFileSync(pagesPath, 'utf-8');
309
+
310
+ if (content.includes(`route: '/${this.appName}'`)) {
311
+ this.logger.verbose(`Route "/${this.appName}" already in mock pages, skipping`);
312
+ return;
313
+ }
314
+
315
+ // 找出已有的最大 id
316
+ const idMatches = [...content.matchAll(/id:\s*(\d+)/g)];
317
+ const maxId = idMatches.reduce((max, m) => Math.max(max, Number(m[1])), 0);
318
+
319
+ const newEntry = [
320
+ ' {',
321
+ ` id: ${maxId + 1},`,
322
+ ` name: '${this.appNamePascal}',`,
323
+ ` nameEn: '${this.appNamePascal}',`,
324
+ ` nameKey: 'page.${this.appName}',`,
325
+ ` route: '/${this.appName}',`,
326
+ ` base: '/${this.appName}',`,
327
+ ` htmlUrl: '//localhost:${this.devPort}',`,
328
+ ' jsUrls: [],',
329
+ ' cssUrls: [],',
330
+ " prefixPath: '',",
331
+ " routeMode: 'prefix',",
332
+ ' enabled: true,',
333
+ ' accessControlEnabled: false,',
334
+ ' adminOnly: false,',
335
+ ' routeKey: null,',
336
+ ` mainDocumentId: ${maxId + 1},`,
337
+ " version: '',",
338
+ ' },',
339
+ ].join('\n');
340
+
341
+ // 插入到兜底路由 (route: '/*') 之前
342
+ const lines = content.split('\n');
343
+ let insertIdx = -1;
344
+
345
+ for (let i = 0; i < lines.length; i++) {
346
+ if (lines[i].includes("route: '/*'")) {
347
+ for (let j = i - 1; j >= 0; j--) {
348
+ if (lines[j].trim() === '{') {
349
+ insertIdx = j;
350
+ break;
351
+ }
352
+ }
353
+ break;
354
+ }
355
+ }
356
+
357
+ if (insertIdx === -1) {
358
+ const closingIdx = lines.findIndex((l) => l.trim() === '];');
359
+ if (closingIdx > 0) insertIdx = closingIdx;
360
+ }
361
+
362
+ if (insertIdx > 0) {
363
+ lines.splice(insertIdx, 0, newEntry);
364
+ fs.writeFileSync(pagesPath, lines.join('\n'), 'utf-8');
365
+ this.log(` 📝 已将 "${this.appName}" 的页面配置添加到 mock/pages.ts`);
366
+ }
367
+ } catch (e) {
368
+ console.warn(` ⚠️ 更新 mock/pages.ts 失败: ${e.message}`);
369
+ }
370
+ }
371
+
372
+ _updateConfigDev() {
373
+ const configPath = path.join(this.monorepoRoot, 'apps/layout/config/config.dev.ts');
374
+ if (!fs.existsSync(configPath)) {
375
+ this.logger.verbose('apps/layout/config/config.dev.ts not found, skipping');
376
+ return;
377
+ }
378
+
379
+ try {
380
+ const content = fs.readFileSync(configPath, 'utf-8');
381
+ const routeEntry = `'/${this.appName}/*'`;
382
+
383
+ if (content.includes(routeEntry)) {
384
+ this.logger.verbose(`Route "${routeEntry}" already in noPermissionRouteList, skipping`);
385
+ return;
386
+ }
387
+
388
+ const updated = content.replace(
389
+ /noPermissionRouteList:\s*\[([^\]]*)\]/,
390
+ (match, inner) => {
391
+ const trimmed = inner.trim();
392
+ const entries = trimmed ? `${trimmed}, ${routeEntry}` : routeEntry;
393
+ return `noPermissionRouteList: [${entries}]`;
394
+ },
395
+ );
396
+
397
+ if (updated === content) {
398
+ this.logger.verbose('noPermissionRouteList not found in config.dev.ts, skipping');
399
+ return;
400
+ }
401
+
402
+ fs.writeFileSync(configPath, updated, 'utf-8');
403
+ this.log(` 📝 已将 "${routeEntry}" 添加到 config.dev.ts 的 noPermissionRouteList 中`);
404
+ } catch (e) {
405
+ console.warn(` ⚠️ 更新 config.dev.ts 失败: ${e.message}`);
406
+ }
407
+ }
408
+
409
+ install() {
410
+ // 跳过 dry-run 模式
411
+ if (this._skipInstall) return;
412
+
413
+ this.log('');
414
+ this.log('📦 正在安装依赖...');
415
+ try {
416
+ this.spawnCommandSync('pnpm', ['install'], {
417
+ cwd: this.monorepoRoot
418
+ });
419
+ } catch (e) {
420
+ this._installFailed = true;
421
+ this.log('');
422
+ this.log('⚠️ 依赖安装失败,但子应用文件已全部生成。');
423
+ this.logger.verbose('Install error:', e.message);
424
+ return;
425
+ }
426
+
427
+ // 依赖安装成功后,格式化被修改的 layout 文件
428
+ const layoutDir = path.join(this.monorepoRoot, 'apps/layout');
429
+ if (fs.existsSync(path.join(layoutDir, '.prettierrc'))) {
430
+ const filesToFormat = [
431
+ path.join(layoutDir, 'mock/pages.ts'),
432
+ path.join(layoutDir, 'config/config.dev.ts'),
433
+ ].filter((f) => fs.existsSync(f));
434
+
435
+ if (filesToFormat.length > 0) {
436
+ try {
437
+ this.spawnCommandSync(
438
+ 'pnpm',
439
+ ['-C', 'apps/layout', 'exec', 'prettier', '--write', ...filesToFormat],
440
+ { cwd: this.monorepoRoot },
441
+ );
442
+ } catch (e) {
443
+ this.logger.verbose('Formatting failed (non-critical):', e.message);
444
+ }
445
+ }
446
+ }
447
+ }
448
+
180
449
  end() {
450
+ // 跳过 dry-run 模式
451
+ if (this._skipInstall) return;
452
+
453
+ this.log('');
454
+
455
+ if (this._installFailed) {
456
+ this.log('⚠️ 子应用文件已创建,但依赖安装未完成。');
457
+ this.log('');
458
+ this.log(' 请手动安装依赖:');
459
+ this.log('');
460
+ this.log(' pnpm install');
461
+ this.log('');
462
+ this.log(' 如果安装仍然失败,可尝试:');
463
+ this.log(' pnpm install --network-concurrency 4');
464
+ } else {
465
+ this.log('✅ 子应用创建成功!');
466
+ }
467
+
181
468
  this.log('');
182
- this.log('✅ 子应用创建成功!');
469
+ this.log(' 后续步骤:');
183
470
  this.log('');
184
471
  this.log(` cd apps/${this.appName}`);
185
- this.log(' pnpm install');
186
472
  this.log(' pnpm dev');
187
473
  this.log('');
188
474
  }
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "subapp-react",
3
+ "description": "在现有 Monorepo 中创建 React 微前端子应用",
4
+ "usage": "cd <monorepo-root> && mico create subapp-react",
5
+ "features": [
6
+ "UmiJS 4 + React 18",
7
+ "qiankun 子应用配置",
8
+ "自动继承主应用主题和请求模块"
9
+ ]
10
+ }
@@ -1,4 +1,5 @@
1
1
  # Default: 5
2
2
  CHECK_TIMEOUT=10
3
3
  DID_YOU_KNOW=none
4
- PORT=8010
4
+ PORT=<%= devPort %>
5
+ SOCKET_SERVER=http://localhost:<%= devPort %>
@@ -89,12 +89,12 @@ PORT=8001
89
89
  }
90
90
  ```
91
91
 
92
- ## 共享依赖
92
+ ## 主题变量
93
93
 
94
- 如项目配置了共享样式包,可在 Less 文件中引入:
94
+ 使用 @mico-platform/theme 时,在 Less 中引入:
95
95
 
96
96
  ```less
97
- @import '@your-scope/shared-styles/variables';
97
+ @import '@mico-platform/theme/variables';
98
98
  ```
99
99
 
100
100
  ## 相关文档
@@ -2,6 +2,13 @@
2
2
 
3
3
  import { defineConfig } from '@umijs/max';
4
4
 
5
+ /**
6
+ * ⚠️⚠️ 不要修改这个变量名,版本升级工具会读取这个变量名,进行版本升级
7
+ * @name mico-ui 版本
8
+ * @description 开发环境使用 mico-ui 的最新版本
9
+ */
10
+ const MICO_UI_VERSION = '<%= micoUiVersionExact %>';
11
+
5
12
  /**
6
13
  * 开发环境配置
7
14
  * - 不配置 externals,直接打包依赖,方便独立运行调试
@@ -22,17 +29,17 @@ const config: ReturnType<typeof defineConfig> = {
22
29
  // headScripts: [
23
30
  // 'https://unpkg.com/react@18/umd/react.development.js',
24
31
  // 'https://unpkg.com/react-dom@18/umd/react-dom.development.js',
25
- // 'https://unpkg.com/@arco-design/web-react@latest/dist/arco.min.js',
32
+ // 'https://unpkg.com/@mico-platform/ui@<%= micoUiVersionExact %>/dist/arco.min.js',
26
33
  // ],
27
34
 
28
35
  // /**
29
36
  // * @name 样式加载配置
30
- // * @description 开发环境独立运行时加载 Arco Design CSS
37
+ // * @description 开发环境独立运行时加载 @mico-platform/ui CSS
31
38
  // */
32
39
  // links: [
33
40
  // {
34
41
  // rel: 'stylesheet',
35
- // href: 'https://unpkg.com/@arco-design/web-react@latest/dist/css/arco.min.css',
42
+ // href: 'https://unpkg.com/@mico-platform/ui@<%= micoUiVersionExact %>/dist/css/arco.min.css',
36
43
  // },
37
44
  // ],
38
45
 
@@ -43,16 +50,16 @@ const config: ReturnType<typeof defineConfig> = {
43
50
  // externals: {
44
51
  // react: 'window.React',
45
52
  // 'react-dom': 'window.ReactDOM',
46
- // '@arco-design/web-react': 'window.arco',
53
+ // '@mico-platform/ui': 'window.micoUI',
47
54
  // },
48
55
  /**
49
56
  * @name 样式加载配置
50
- * @description 开发环境独立运行时加载 Arco Design CSS
57
+ * @description 开发环境独立运行时加载 @mico-platform/ui CSS
51
58
  * 作为微前端子应用运行时,样式由主应用提供
52
59
  */
53
60
  styles: [
54
- // Arco Design 基础样式
55
- 'https://unpkg.com/@arco-design/web-react@2.66.6/dist/css/arco.min.css',
61
+ // @mico-platform/ui 基础样式(使用运行时解析的最新版本号,避免 latest 标签)
62
+ `https://cdn-portal.micoplatform.com/portal-center/mico-ui/${MICO_UI_VERSION}/ui/dist/css/mico-ui.min.css`,
56
63
  ],
57
64
  };
58
65
 
@@ -1,25 +1,35 @@
1
1
  // https://umijs.org/config/
2
2
 
3
3
  import { defineConfig } from '@umijs/max';
4
+ // 开发环境,不上传 sourcemap。调试时如有需要再解开
5
+ // import { applySentryPlugin } from "../../../scripts/apply-sentry-plugin";
4
6
  const { CDN_PUBLIC_PATH } = process.env;
5
7
 
6
8
  const PUBLIC_PATH: string = CDN_PUBLIC_PATH
7
- ? `${CDN_PUBLIC_PATH.replace(/\/?$/, '/')}homepage/`
8
- : '/homepage/';
9
+ ? `${CDN_PUBLIC_PATH.replace(/\/?$/, '/')}<%= appName %>/`
10
+ : '/<%= appName %>/';
9
11
 
10
12
  const config: ReturnType<typeof defineConfig> = {
13
+ // 开发环境,不上传 sourcemap。调试时如有需要再解开
14
+ // devtool: 'hidden-source-map',
15
+
11
16
  // 测试环境:将所有代码打包到一个文件
12
17
  extraBabelPlugins: ['babel-plugin-dynamic-import-node'],
13
18
 
19
+ publicPath: PUBLIC_PATH,
20
+ cssPublicPath: PUBLIC_PATH,
21
+
14
22
  // 禁用代码分割,只输出一个 JS 和一个 CSS
15
23
  chainWebpack(memo) {
16
24
  // 禁用 splitChunks
17
25
  memo.optimization.splitChunks(false);
18
26
  // 禁用 runtimeChunk
19
27
  memo.optimization.runtimeChunk(false);
28
+ memo.plugins.delete('runtimePublicPath');
29
+ // 开发环境,不上传 sourcemap。调试时如有需要再解开
30
+ // applySentryPlugin({ memo, appName: '<%= appName %>' });
20
31
  return memo;
21
32
  },
22
- publicPath: PUBLIC_PATH,
23
33
 
24
34
  /**
25
35
  * @name 外部依赖配置
@@ -28,12 +38,13 @@ const config: ReturnType<typeof defineConfig> = {
28
38
  *
29
39
  * 作为 qiankun 子应用时,这些库由主应用提供:
30
40
  * - react / react-dom: 主应用已加载,避免多实例问题
31
- * - @arco-design/web-react: 主应用已加载,复用组件和样式
41
+ * - @mico-platform/ui: 主应用已加载,复用组件和样式
32
42
  */
33
43
  externals: {
34
44
  react: 'React',
35
45
  'react-dom': 'ReactDOM',
36
- '@arco-design/web-react': 'arco',
46
+ '@mico-platform/ui': 'micoUI',
47
+ '@common-web/sentry': 'CommonWebSentry',
37
48
  },
38
49
  };
39
50
 
@@ -1,25 +1,35 @@
1
1
  // https://umijs.org/config/
2
2
 
3
3
  import { defineConfig } from '@umijs/max';
4
+ // 测试环境,不上传 sourcemap。调试时如有需要再解开
5
+ // import { applySentryPlugin } from "../../../scripts/apply-sentry-plugin";
4
6
  const { CDN_PUBLIC_PATH } = process.env;
5
7
 
6
8
  const PUBLIC_PATH: string = CDN_PUBLIC_PATH
7
- ? `${CDN_PUBLIC_PATH.replace(/\/?$/, '/')}homepage/`
8
- : '/homepage/';
9
+ ? `${CDN_PUBLIC_PATH.replace(/\/?$/, '/')}<%= appName %>/`
10
+ : '/<%= appName %>/';
9
11
 
10
12
  const config: ReturnType<typeof defineConfig> = {
13
+ // 测试环境,不上传 sourcemap。调试时如有需要再解开
14
+ // devtool: 'hidden-source-map',
15
+
11
16
  // 测试环境:将所有代码打包到一个文件
12
17
  extraBabelPlugins: ['babel-plugin-dynamic-import-node'],
13
18
 
19
+ publicPath: PUBLIC_PATH,
20
+ cssPublicPath: PUBLIC_PATH,
21
+
14
22
  // 禁用代码分割,只输出一个 JS 和一个 CSS
15
23
  chainWebpack(memo) {
16
24
  // 禁用 splitChunks
17
25
  memo.optimization.splitChunks(false);
18
26
  // 禁用 runtimeChunk
19
27
  memo.optimization.runtimeChunk(false);
28
+ memo.plugins.delete('runtimePublicPath');
29
+ // 测试环境,不上传 sourcemap。调试时如有需要再解开
30
+ // applySentryPlugin({ memo, appName: '<%= appName %>' });
20
31
  return memo;
21
32
  },
22
- publicPath: PUBLIC_PATH,
23
33
 
24
34
  /**
25
35
  * @name 外部依赖配置
@@ -28,12 +38,13 @@ const config: ReturnType<typeof defineConfig> = {
28
38
  *
29
39
  * 作为 qiankun 子应用时,这些库由主应用提供:
30
40
  * - react / react-dom: 主应用已加载,避免多实例问题
31
- * - @arco-design/web-react: 主应用已加载,复用组件和样式
41
+ * - @mico-platform/ui: 主应用已加载,复用组件和样式
32
42
  */
33
43
  externals: {
34
44
  react: 'React',
35
45
  'react-dom': 'ReactDOM',
36
- '@arco-design/web-react': 'arco',
46
+ '@mico-platform/ui': 'micoUI',
47
+ '@common-web/sentry': 'CommonWebSentry',
37
48
  },
38
49
  };
39
50