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
package/README.md CHANGED
@@ -9,39 +9,89 @@
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 组件包生成器说明 |
13
+ | [docs/feat-integration-tests.md](docs/feat-integration-tests.md) | 集成测试方案(Vitest + yeoman-test) |
14
+ | [docs/fix-command-injection.md](docs/fix-command-injection.md) | 修复 npm version 查询命令注入风险 |
15
+ | [docs/refactor-code-quality-optimizations.md](docs/refactor-code-quality-optimizations.md) | 代码质量优化(DRY / 错误处理 / 确定性 ID / 可配置化 / 冗余清理) |
12
16
 
13
17
  ## 要求
14
18
 
15
19
  - Node >= 18
16
- - Yeoman CLI: `npm install -g yo`
17
20
 
18
21
  ## 安装和使用
19
22
 
20
23
  ```bash
21
- npm install -g yo generator-mico-cli
24
+ npm install -g generator-mico-cli
22
25
  ```
23
26
 
24
27
  ## 包装器 CLI
25
28
 
26
- 全局安装后,`mico` 命令可用于委托给 Yeoman 生成器。
27
- 如果 `generators/<name>` 下存在本地生成器,它将作为 `yo mico-cli:<name>` 运行。
29
+ 全局安装后,`mico` 命令可用于运行内置的 Yeoman 生成器。
28
30
 
29
31
  ```bash
30
32
  mico create subapp-react
31
33
  ```
32
34
 
33
- 等同于:
35
+ 列出所有可用的生成器:
34
36
 
35
37
  ```bash
36
- yo subapp-react
38
+ mico list
37
39
  ```
38
40
 
39
- 将额外参数传递给生成器:
41
+ 使用详细输出模式(显示文件处理过程):
40
42
 
41
43
  ```bash
42
- mico create micro-react -- --help
44
+ mico create micro-react --verbose
43
45
  ```
44
46
 
47
+ 预览模式(只显示将创建的文件,不实际创建):
48
+
49
+ ```bash
50
+ mico create micro-react --dry-run
51
+ ```
52
+
53
+ 检查环境依赖:
54
+
55
+ ```bash
56
+ mico doctor
57
+ ```
58
+
59
+ ## 配置文件
60
+
61
+ 可以在项目目录或用户主目录创建 `.micorc` 或 `.micorc.json` 文件来预设默认值。
62
+
63
+ 配置查找顺序:
64
+ 1. 当前目录(或 monorepo 根目录)的 `.micorc` / `.micorc.json`
65
+ 2. 用户主目录的 `.micorc` / `.micorc.json`
66
+
67
+ ### 完整字段列表
68
+
69
+ ```json
70
+ {
71
+ "projectName": "my-app",
72
+ "packageScope": "@my-company",
73
+ "cdnPrefix": "portal",
74
+ "author": "Team <team@example.com>",
75
+ "defaultSubappName": "subapp",
76
+ "devPort": "8010",
77
+ "defaultUmdName": "my-widget",
78
+ "umdDevPort": "9100"
79
+ }
80
+ ```
81
+
82
+ | 字段 | 类型 | 适用生成器 | 说明 | 默认值 |
83
+ |------|------|-----------|------|--------|
84
+ | `projectName` | string | micro-react | 项目名称 | 当前目录名 |
85
+ | `packageScope` | string | 所有 | 包作用域(如 `@my-company`) | micro-react: `@<projectName>`;其他: 从根 `package.json` 检测 |
86
+ | `cdnPrefix` | string | micro-react | CDN 路径前缀(如 `portal`、`admin/v2`) | 空字符串 |
87
+ | `author` | string | micro-react | 作者信息 | `Your Name <email@example.com>` |
88
+ | `defaultSubappName` | string | subapp-react | 子应用默认名称 | `subapp` |
89
+ | `devPort` | string | subapp-react | 子应用开发端口 | `8010` |
90
+ | `defaultUmdName` | string | subapp-umd | UMD 包默认名称 | `my-widget` |
91
+ | `umdDevPort` | string | subapp-umd | UMD 包开发端口 | `9100` |
92
+
93
+ 所有字段均为可选,未配置时使用默认值或交互式提示。
94
+
45
95
  ## Monorepo 项目生成器 (micro-react)
46
96
 
47
97
  创建基于 qiankun 微前端架构的完整 Monorepo 项目:
@@ -53,9 +103,10 @@ mico create micro-react
53
103
 
54
104
  生成的项目包含:
55
105
  - 主应用 (layout) - qiankun master
56
- - 共享样式包 (shared-styles)
106
+ - @mico-platform/ui、@mico-platform/theme
57
107
  - Turborepo + pnpm Workspace
58
108
  - Husky + Commitlint
109
+ - @common-web/sentry 错误监控与 SourceMap 上传
59
110
 
60
111
  ## React 子应用生成器
61
112
 
@@ -67,18 +118,151 @@ cd <monorepo-root>
67
118
  mico create subapp-react
68
119
  ```
69
120
 
70
- ## 同步子应用模板
121
+ ## UMD 组件包生成器
122
+
123
+ 在 Monorepo 的 `packages/` 目录下创建 UMD 格式的组件包,使用 Webpack 构建。适用于通过 `<script>` 标签加载的场景(如主应用菜单挂载组件、第三方系统嵌入 Widget 等)。
124
+
125
+ ```bash
126
+ cd <monorepo-root>
127
+ mico create subapp-umd
128
+ ```
129
+
130
+ 生成器会提示输入:
131
+ - **Package name** — 包名(如 `my-widget`)
132
+ - **UMD global variable name** — 全局变量名(如 `MyWidget`)
133
+ - **Package scope** — 包作用域(自动从根 `package.json` 检测)
134
+ - **Dev server port** — 开发端口(默认 `9100`)
135
+
136
+ 生成的包支持:
137
+ - `pnpm dev` — 启动 webpack-dev-server,同时提供 HTML 预览页和 UMD JS 文件
138
+ - `pnpm build` — 构建生产环境 UMD 产物到 `dist/`
139
+
140
+ 开发模式下:
141
+
142
+ | URL | 用途 |
143
+ |---|---|
144
+ | `http://localhost:<port>/` | HTML 预览页,独立调试 |
145
+ | `http://localhost:<port>/<name>.umd.js` | UMD JS 文件,供主应用通过 `jsUrls` 联调 |
146
+
147
+ DevTools Sources 面板中可在 `webpack://<name>/src/` 下定位原始 TypeScript 源码进行断点调试。
148
+
149
+ ## 开发指南
150
+
151
+ ### 环境准备
152
+
153
+ ```bash
154
+ # 1. 安装依赖
155
+ pnpm install
156
+
157
+ # 2. 将本地包链接到全局
158
+ npm link
159
+
160
+ # 3. 验证链接成功
161
+ mico --version
162
+ ```
163
+
164
+ 链接成功后,`mico` 命令会使用本地代码,可以直接修改代码并测试:
165
+
166
+ ```bash
167
+ # 测试 micro-react 生成器
168
+ mkdir test-project && cd test-project
169
+ mico create micro-react
170
+
171
+ # 测试 subapp-react 生成器(需在已有 monorepo 中执行)
172
+ mico create subapp-react
173
+
174
+ # 测试 subapp-umd 生成器(需在已有 monorepo 中执行)
175
+ mico create subapp-umd
176
+ ```
177
+
178
+ 调试完成后,取消全局链接:
179
+
180
+ ```bash
181
+ npm unlink -g generator-mico-cli
182
+ ```
183
+
184
+ ### 运行测试
71
185
 
72
- 将源项目的 `apps/homepage` 同步到生成器模板目录:
186
+ 项目使用 Vitest + yeoman-test 进行单元测试和集成测试:
73
187
 
74
188
  ```bash
75
- SOURCE_PROJECT_ROOT=<source-project-root> npm run sync:subapp-react-template
189
+ # 运行全部测试
190
+ pnpm test
191
+
192
+ # watch 模式
193
+ pnpm test:watch
76
194
  ```
77
195
 
78
- 也可以直接传入路径:
196
+ 测试目录结构:
197
+
198
+ | 目录/文件 | 说明 |
199
+ |----------|------|
200
+ | `tests/unit/utils.test.js` | `lib/utils.js` 的单元测试 |
201
+ | `tests/integration/micro-react.test.js` | micro-react 生成器集成测试 |
202
+ | `tests/integration/subapp-react.test.js` | subapp-react 生成器集成测试 |
203
+ | `tests/integration/subapp-umd.test.js` | subapp-umd 生成器集成测试 |
204
+ | `tests/integration/mico-cli.test.js` | `mico` 入口子进程测试(help / version / list / create / doctor) |
205
+ | `tests/helpers/setup.js` | 测试共享工具(路径常量、monorepo fixture 工厂) |
206
+ | `tests/helpers/mico-subprocess.js` | 子进程运行 `bin/mico.js` 工具函数 |
207
+
208
+ ### Scripts 说明
209
+
210
+ | 脚本 | 命令 | 说明 |
211
+ |------|------|------|
212
+ | `sync:subapp-react-template` | `pnpm run sync:subapp-react-template -- <source-path>` | 将源项目的 `apps/homepage` 同步到 `subapp-react` 模板目录,忽略清单见 `generators/subapp-react/ignore-list.json` |
213
+ | `verify:micro-react` | `node scripts/verify-micro-react.js [test-dir]` | 端到端验证 micro-react + subapp-react 生成器,自动创建项目并回车通过所有提示 |
214
+
215
+ #### verify-micro-react.js
216
+
217
+ 自动化验证脚本,依次执行:
218
+ 1. 创建或清空测试目录
219
+ 2. 运行 `mico create micro-react`(自动回车通过 5 个提示)
220
+ 3. 运行 `mico create subapp-react`(自动回车通过 4 个提示)
221
+
222
+ 测试目录支持三种方式指定:
223
+ - 命令行参数:`node scripts/verify-micro-react.js /path/to/dir`
224
+ - 环境变量:`VERIFY_TEST_DIR=/path node scripts/verify-micro-react.js`
225
+ - 默认值:`../test-app2`
226
+
227
+ #### sync-subapp-react-template.js
228
+
229
+ 从源 monorepo 项目同步 `apps/homepage` 到生成器模板目录:
79
230
 
80
231
  ```bash
81
- npm run sync:subapp-react-template -- <source-project-root>
232
+ # 通过环境变量
233
+ SOURCE_PROJECT_ROOT=<source-path> pnpm run sync:subapp-react-template
234
+
235
+ # 通过命令行参数
236
+ pnpm run sync:subapp-react-template -- <source-path>
237
+ ```
238
+
239
+ 会自动记录源仓库的 git commit 信息到 `.template-version.json`。
240
+
241
+ ### 项目结构
242
+
243
+ ```
244
+ mico-cli/
245
+ ├── bin/mico.js # CLI 入口(命令解析、生成器调度)
246
+ ├── lib/utils.js # 共享工具函数(字符串转换、文件处理、npm 版本查询、配置加载)
247
+ ├── generators/
248
+ │ ├── micro-react/ # Monorepo 项目生成器
249
+ │ ├── subapp-react/ # React 子应用生成器
250
+ │ └── subapp-umd/ # UMD 组件包生成器
251
+ ├── scripts/ # 辅助脚本
252
+ ├── tests/ # 测试文件
253
+ ├── docs/ # 功能文档
254
+ └── vitest.config.js # 测试配置
82
255
  ```
83
256
 
84
- 忽略清单位于 `generators/subapp-react/ignore-list.json`。
257
+ ### 提交规范
258
+
259
+ 请使用语义化提交信息:
260
+
261
+ ```
262
+ feat: 添加新功能
263
+ fix: 修复 Bug
264
+ refactor: 代码重构
265
+ docs: 文档更新
266
+ test: 测试相关
267
+ chore: 构建/工具链变更
268
+ ```
package/bin/mico.js CHANGED
@@ -1,11 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- const { spawn, spawnSync } = require('node:child_process');
4
+ const { spawnSync } = require('node:child_process');
5
5
  const fs = require('node:fs');
6
6
  const path = require('node:path');
7
7
  const readline = require('node:readline');
8
8
 
9
+ const { setupErrorHandlers } = require('../lib/utils');
10
+
11
+ setupErrorHandlers();
12
+
9
13
  const rootDir = path.resolve(__dirname, '..');
10
14
  const pkg = JSON.parse(
11
15
  fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8')
@@ -20,24 +24,112 @@ Usage: mico <command> [options]
20
24
 
21
25
  Commands:
22
26
  create <generator> Run a generator (e.g., mico create subapp-react)
27
+ list List all available generators
23
28
  update Update mico-cli to the latest version
29
+ doctor Check environment dependencies
24
30
 
25
31
  Options:
26
32
  --help, -h Show this help message
27
33
  --version, -v Show version number
34
+ --verbose Show detailed output during generation
35
+ --dry-run Preview files without creating them
36
+ --force Overwrite all existing files without confirmation
28
37
  --no-update-check Skip update check
29
38
 
30
39
  Examples:
31
40
  mico create subapp-react
32
- mico create app
41
+ mico create micro-react --verbose
42
+ mico create micro-react --dry-run
43
+ mico create micro-react --force
44
+ mico list
33
45
  mico update
46
+ mico doctor
47
+
48
+ Configuration:
49
+ Create a .micorc or .micorc.json file in your project or home directory
50
+ to set default values for prompts:
51
+
52
+ {
53
+ "packageScope": "@my-company",
54
+ "cdnPrefix": "portal",
55
+ "author": "Team <team@example.com>"
56
+ }
34
57
 
35
58
  Notes:
36
- Requires Yeoman CLI (yo) installed globally.
37
59
  If a local generator exists at generators/<name>, it will be used.
38
60
  `);
39
61
  }
40
62
 
63
+ /**
64
+ * 列出所有可用的生成器
65
+ */
66
+ function listGenerators() {
67
+ const generatorsDir = path.join(rootDir, 'generators');
68
+
69
+ if (!fs.existsSync(generatorsDir)) {
70
+ console.error('❌ Error: generators directory not found.');
71
+ process.exit(1);
72
+ }
73
+
74
+ const entries = fs.readdirSync(generatorsDir, { withFileTypes: true });
75
+ const generators = [];
76
+
77
+ for (const entry of entries) {
78
+ if (!entry.isDirectory()) continue;
79
+
80
+ const generatorPath = path.join(generatorsDir, entry.name);
81
+ const indexPath = path.join(generatorPath, 'index.js');
82
+ const metaPath = path.join(generatorPath, 'meta.json');
83
+
84
+ // 必须有 index.js 才算有效生成器
85
+ if (!fs.existsSync(indexPath)) continue;
86
+
87
+ let meta = { name: entry.name, description: '(No description)' };
88
+ if (fs.existsSync(metaPath)) {
89
+ try {
90
+ meta = { ...meta, ...JSON.parse(fs.readFileSync(metaPath, 'utf8')) };
91
+ } catch (e) {
92
+ console.warn(` ⚠ Failed to parse ${metaPath}: ${e.message}`);
93
+ }
94
+ }
95
+
96
+ generators.push(meta);
97
+ }
98
+
99
+ if (generators.length === 0) {
100
+ console.log('');
101
+ console.log(' No generators found.');
102
+ console.log('');
103
+ return;
104
+ }
105
+
106
+ console.log('');
107
+ console.log(` \x1b[1mAvailable Generators\x1b[0m (mico-cli v${pkg.version})`);
108
+ console.log('');
109
+
110
+ // 计算最长名称用于对齐
111
+ const maxNameLen = Math.max(...generators.map((g) => g.name.length));
112
+
113
+ for (const gen of generators) {
114
+ const name = gen.name.padEnd(maxNameLen + 2);
115
+ console.log(` \x1b[36m${name}\x1b[0m ${gen.description}`);
116
+
117
+ // 如果有 features,显示特性列表
118
+ if (gen.features && gen.features.length > 0) {
119
+ for (const feature of gen.features) {
120
+ console.log(` ${' '.repeat(maxNameLen + 2)} • ${feature}`);
121
+ }
122
+ }
123
+
124
+ // 如果有 usage,显示用法
125
+ if (gen.usage) {
126
+ console.log(` ${' '.repeat(maxNameLen + 2)} \x1b[2m$ ${gen.usage}\x1b[0m`);
127
+ }
128
+
129
+ console.log('');
130
+ }
131
+ }
132
+
41
133
  /**
42
134
  * 打印版本信息
43
135
  */
@@ -45,6 +137,76 @@ function printVersion() {
45
137
  console.log(`mico-cli v${pkg.version}`);
46
138
  }
47
139
 
140
+ /**
141
+ * 运行 doctor 检查
142
+ */
143
+ async function runDoctor() {
144
+ const { runDoctorChecks, loadMicorc } = require('../lib/utils');
145
+
146
+ console.log('');
147
+ console.log(` \x1b[1mMico CLI Environment Check\x1b[0m (v${pkg.version})`);
148
+ console.log('');
149
+
150
+ const results = await runDoctorChecks();
151
+
152
+ // Node.js
153
+ const nodeIcon = results.node.satisfied ? '\x1b[32m✓\x1b[0m' : '\x1b[31m✗\x1b[0m';
154
+ const nodeStatus = results.node.satisfied ? 'OK' : `Required: >= ${results.node.required}`;
155
+ console.log(` ${nodeIcon} Node.js ${results.node.current} (${nodeStatus})`);
156
+
157
+ // pnpm
158
+ const pnpmIcon = results.pnpm.available ? '\x1b[32m✓\x1b[0m' : '\x1b[31m✗\x1b[0m';
159
+ if (results.pnpm.available) {
160
+ console.log(` ${pnpmIcon} pnpm ${results.pnpm.version}`);
161
+ } else {
162
+ console.log(` ${pnpmIcon} pnpm not found`);
163
+ console.log(' Install: npm install -g pnpm');
164
+ }
165
+
166
+ // Git
167
+ const gitIcon = results.git.available ? '\x1b[32m✓\x1b[0m' : '\x1b[33m⚠\x1b[0m';
168
+ if (results.git.available) {
169
+ console.log(` ${gitIcon} git ${results.git.version}`);
170
+ } else {
171
+ console.log(` ${gitIcon} git not found (optional)`);
172
+ }
173
+
174
+ // npm registry
175
+ const npmIcon = results.npm.reachable ? '\x1b[32m✓\x1b[0m' : '\x1b[33m⚠\x1b[0m';
176
+ if (results.npm.reachable) {
177
+ console.log(` ${npmIcon} npm registry reachable`);
178
+ } else {
179
+ console.log(` ${npmIcon} npm registry unreachable (${results.npm.error})`);
180
+ }
181
+
182
+ // .micorc 配置
183
+ console.log('');
184
+ const { config, configPath } = loadMicorc();
185
+ if (configPath) {
186
+ console.log(` \x1b[32m✓\x1b[0m Config loaded from: ${configPath}`);
187
+ const keys = Object.keys(config);
188
+ if (keys.length > 0) {
189
+ console.log(` Keys: ${keys.join(', ')}`);
190
+ }
191
+ } else {
192
+ console.log(' \x1b[2m○\x1b[0m No .micorc config found (optional)');
193
+ }
194
+
195
+ console.log('');
196
+
197
+ // 总结
198
+ const allGood = results.node.satisfied && results.pnpm.available;
199
+ if (allGood) {
200
+ console.log(' \x1b[32m✅ All required dependencies are installed!\x1b[0m');
201
+ } else {
202
+ console.log(' \x1b[31m❌ Some required dependencies are missing.\x1b[0m');
203
+ console.log(' Please install them before using mico-cli.');
204
+ }
205
+ console.log('');
206
+
207
+ return allGood;
208
+ }
209
+
48
210
  /**
49
211
  * 检查是否有新版本
50
212
  * @returns {Promise<{current: string, latest: string, hasUpdate: boolean} | null>}
@@ -178,8 +340,13 @@ function performUpdate(latestVersion) {
178
340
 
179
341
  /**
180
342
  * 运行 Yeoman 生成器
343
+ * @param {string} generator - 生成器名称
344
+ * @param {object} options - 选项
345
+ * @param {boolean} options.verbose - 是否启用详细输出
346
+ * @param {boolean} options.dryRun - 是否启用 dry-run 模式
347
+ * @param {boolean} options.force - 是否强制覆盖已有文件
181
348
  */
182
- function runGenerator(generator, rest, passthroughArgs) {
349
+ async function runGenerator(generator, options = {}) {
183
350
  const localGeneratorEntry = path.join(
184
351
  rootDir,
185
352
  'generators',
@@ -187,34 +354,50 @@ function runGenerator(generator, rest, passthroughArgs) {
187
354
  'index.js'
188
355
  );
189
356
 
357
+ if (!fs.existsSync(localGeneratorEntry)) {
358
+ console.error(`❌ Cannot find generator "${generator}".`);
359
+ console.error(` Expected: ${localGeneratorEntry}`);
360
+ console.error('');
361
+ console.error(' Run "mico list" to see available generators.');
362
+ process.exit(1);
363
+ }
364
+
190
365
  const pkgName = typeof pkg.name === 'string' ? pkg.name : '';
191
366
  const localNamespace =
192
367
  pkgName.replace(/^generator-/, '') || pkgName || 'generator';
368
+ const namespace = `${localNamespace}:${generator}`;
193
369
 
194
- const yoGenerator = fs.existsSync(localGeneratorEntry)
195
- ? `${localNamespace}:${generator}`
196
- : generator;
197
-
198
- const yoArgs = [yoGenerator, ...rest];
199
-
200
- if (passthroughArgs.length > 0) {
201
- yoArgs.push('--', ...passthroughArgs);
370
+ if (options.verbose) {
371
+ process.env.MICO_VERBOSE = '1';
372
+ }
373
+ if (options.dryRun) {
374
+ process.env.MICO_DRY_RUN = '1';
202
375
  }
203
376
 
204
- const child = spawn('yo', yoArgs, { stdio: 'inherit' });
377
+ const runOptions = {};
378
+ if (options.dryRun) {
379
+ runOptions.dryRun = true;
380
+ }
381
+ if (options.force) {
382
+ runOptions.force = true;
383
+ }
205
384
 
206
- child.on('error', (error) => {
207
- if (error && error.code === 'ENOENT') {
208
- console.error('Cannot find "yo". Install it with: npm install -g yo');
209
- } else {
210
- console.error(error);
385
+ if (options.verbose) {
386
+ console.log('');
387
+ console.log(' \x1b[2m[verbose] Running generator:', namespace, '\x1b[0m');
388
+ if (options.dryRun) {
389
+ console.log(' \x1b[2m[verbose] Dry-run mode enabled\x1b[0m');
211
390
  }
212
- process.exit(1);
213
- });
391
+ if (options.force) {
392
+ console.log(' \x1b[2m[verbose] Force mode enabled\x1b[0m');
393
+ }
394
+ console.log('');
395
+ }
214
396
 
215
- child.on('exit', (code) => {
216
- process.exit(typeof code === 'number' ? code : 1);
217
- });
397
+ const yeomanEnv = require('yeoman-environment');
398
+ const env = yeomanEnv.createEnv();
399
+ env.register(localGeneratorEntry, namespace);
400
+ await env.run(namespace, runOptions);
218
401
  }
219
402
 
220
403
  /**
@@ -234,6 +417,9 @@ async function main() {
234
417
  const hasHelp = mainArgs.includes('--help') || mainArgs.includes('-h');
235
418
  const hasVersion = mainArgs.includes('--version') || mainArgs.includes('-v');
236
419
  const skipUpdateCheck = mainArgs.includes('--no-update-check');
420
+ const isVerbose = mainArgs.includes('--verbose');
421
+ const isDryRun = mainArgs.includes('--dry-run');
422
+ const isForce = mainArgs.includes('--force');
237
423
 
238
424
  // 过滤掉标志参数
239
425
  const filteredArgs = mainArgs.filter(
@@ -242,7 +428,10 @@ async function main() {
242
428
  arg !== '-h' &&
243
429
  arg !== '--version' &&
244
430
  arg !== '-v' &&
245
- arg !== '--no-update-check'
431
+ arg !== '--no-update-check' &&
432
+ arg !== '--verbose' &&
433
+ arg !== '--dry-run' &&
434
+ arg !== '--force'
246
435
  );
247
436
 
248
437
  // 处理 --version
@@ -259,6 +448,18 @@ async function main() {
259
448
 
260
449
  const [command, ...rest] = filteredArgs;
261
450
 
451
+ // 处理 list 命令
452
+ if (command === 'list' || command === 'ls') {
453
+ listGenerators();
454
+ process.exit(0);
455
+ }
456
+
457
+ // 处理 doctor 命令
458
+ if (command === 'doctor') {
459
+ const success = await runDoctor();
460
+ process.exit(success ? 0 : 1);
461
+ }
462
+
262
463
  // 处理 update 命令
263
464
  if (command === 'update') {
264
465
  const updateInfo = await checkForUpdate();
@@ -280,8 +481,8 @@ async function main() {
280
481
  process.exit(1);
281
482
  }
282
483
 
283
- // 检查更新(除非跳过)
284
- if (!skipUpdateCheck) {
484
+ // 检查更新(除非跳过或 dry-run)
485
+ if (!skipUpdateCheck && !isDryRun) {
285
486
  const updateInfo = await checkForUpdate();
286
487
  if (updateInfo && updateInfo.hasUpdate) {
287
488
  const shouldUpdate = await askForUpdate(
@@ -300,7 +501,11 @@ async function main() {
300
501
  }
301
502
 
302
503
  // 运行生成器
303
- runGenerator(generator, rest.slice(1), passthroughArgs);
504
+ await runGenerator(generator, {
505
+ verbose: isVerbose,
506
+ dryRun: isDryRun,
507
+ force: isForce
508
+ });
304
509
  return;
305
510
  }
306
511