generator-mico-cli 0.2.31 → 0.2.32

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 (162) hide show
  1. package/README.md +145 -18
  2. package/bin/mico.js +76 -0
  3. package/generators/h5-react/ignore-list.json +1 -0
  4. package/generators/h5-react/index.js +349 -0
  5. package/generators/h5-react/meta.json +11 -0
  6. package/generators/h5-react/templates/.commitlintrc.js +7 -0
  7. package/generators/h5-react/templates/.cursor/rules/cicd-deploy.mdc +104 -0
  8. package/generators/h5-react/templates/.cursor/rules/common-intl.mdc +42 -0
  9. package/generators/h5-react/templates/.cursor/rules/git-hooks.mdc +40 -0
  10. package/generators/h5-react/templates/.cursor/rules/internal-packages.mdc +46 -0
  11. package/generators/h5-react/templates/.cursor/rules/monorepo.mdc +64 -0
  12. package/generators/h5-react/templates/.cursor/rules/package-json.mdc +52 -0
  13. package/generators/h5-react/templates/.cursor/rules/tailwind-umi.mdc +60 -0
  14. package/generators/h5-react/templates/.cursor/rules/umi-app.mdc +74 -0
  15. package/generators/h5-react/templates/.cursor/rules/umi-config.mdc +86 -0
  16. package/generators/h5-react/templates/.cursor/rules/umi-mock.mdc +80 -0
  17. package/generators/h5-react/templates/.cursor/rules/workspace-request.mdc +52 -0
  18. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/SKILL.md +213 -0
  19. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/evals/evals.json +23 -0
  20. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/cursor-rule-template.md +60 -0
  21. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/phase-1-scanning.md +102 -0
  22. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/phase-2-context-analysis.md +102 -0
  23. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/phase-3-pattern-extraction.md +105 -0
  24. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/phase-4-module-mapping.md +65 -0
  25. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/phase-5-glossary.md +63 -0
  26. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/templates/DEV_PATTERNS.tpl.md +77 -0
  27. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/templates/GLOSSARY.tpl.md +17 -0
  28. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/templates/MODULE_MAP.tpl.md +45 -0
  29. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/templates/PROJECT_CONTEXT.tpl.md +155 -0
  30. package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/update-mode.md +116 -0
  31. package/generators/h5-react/templates/.env.development +5 -0
  32. package/generators/h5-react/templates/.env.production +5 -0
  33. package/generators/h5-react/templates/.env.testing +5 -0
  34. package/generators/h5-react/templates/.husky/commit-msg +2 -0
  35. package/generators/h5-react/templates/.husky/pre-commit +2 -0
  36. package/generators/h5-react/templates/.lintstagedrc.js +8 -0
  37. package/generators/h5-react/templates/.prettierrc.json +7 -0
  38. package/generators/h5-react/templates/CICD/before_build.sh +76 -0
  39. package/generators/h5-react/templates/CICD/start_dev.sh +54 -0
  40. package/generators/h5-react/templates/CICD/start_local.sh +30 -0
  41. package/generators/h5-react/templates/CICD/start_prod.sh +53 -0
  42. package/generators/h5-react/templates/CICD/start_test.sh +55 -0
  43. package/generators/h5-react/templates/CICD/wangsu_fresh_dev.sh +19 -0
  44. package/generators/h5-react/templates/CICD/wangsu_fresh_prod.sh +19 -0
  45. package/generators/h5-react/templates/CICD/wangsu_fresh_test.sh +19 -0
  46. package/generators/h5-react/templates/README.md +301 -0
  47. package/generators/h5-react/templates/_gitignore +30 -0
  48. package/generators/h5-react/templates/_npmrc +6 -0
  49. package/generators/h5-react/templates/apps/.gitkeep +0 -0
  50. package/generators/h5-react/templates/dev.preset.json +10 -0
  51. package/generators/h5-react/templates/package.json +56 -0
  52. package/generators/h5-react/templates/packages/common-intl/README.md +180 -0
  53. package/generators/h5-react/templates/packages/common-intl/eslint.config.ts +12 -0
  54. package/generators/h5-react/templates/packages/common-intl/package.json +31 -0
  55. package/generators/h5-react/templates/packages/common-intl/src/index.ts +3 -0
  56. package/generators/h5-react/templates/packages/common-intl/src/intl.ts +100 -0
  57. package/generators/h5-react/templates/packages/common-intl/tsconfig.json +3 -0
  58. package/generators/h5-react/templates/packages/components/eslint.config.ts +12 -0
  59. package/generators/h5-react/templates/packages/components/package.json +32 -0
  60. package/generators/h5-react/templates/packages/components/src/Layout/ImmersiveHeader.tsx +126 -0
  61. package/generators/h5-react/templates/packages/components/src/Layout/LayoutFooter.tsx +72 -0
  62. package/generators/h5-react/templates/packages/components/src/Layout/index.tsx +121 -0
  63. package/generators/h5-react/templates/packages/components/src/assets/image/back.png +0 -0
  64. package/generators/h5-react/templates/packages/components/src/index.ts +0 -0
  65. package/generators/h5-react/templates/packages/components/tsconfig.json +13 -0
  66. package/generators/h5-react/templates/packages/components/typings.d.ts +1 -0
  67. package/generators/h5-react/templates/packages/constant/eslint.config.ts +12 -0
  68. package/generators/h5-react/templates/packages/constant/package.json +19 -0
  69. package/generators/h5-react/templates/packages/constant/src/index.ts +0 -0
  70. package/generators/h5-react/templates/packages/constant/src/member.ts +8 -0
  71. package/generators/h5-react/templates/packages/constant/tsconfig.json +3 -0
  72. package/generators/h5-react/templates/packages/deeplink/eslint.config.ts +12 -0
  73. package/generators/h5-react/templates/packages/deeplink/package.json +18 -0
  74. package/generators/h5-react/templates/packages/deeplink/src/index.ts +7 -0
  75. package/generators/h5-react/templates/packages/deeplink/tsconfig.json +3 -0
  76. package/generators/h5-react/templates/packages/domain/eslint.config.ts +12 -0
  77. package/generators/h5-react/templates/packages/domain/package.json +18 -0
  78. package/generators/h5-react/templates/packages/domain/src/index.ts +29 -0
  79. package/generators/h5-react/templates/packages/domain/tsconfig.json +3 -0
  80. package/generators/h5-react/templates/packages/domain/types.d.ts +11 -0
  81. package/generators/h5-react/templates/packages/eslint/eslint.config.base.ts +36 -0
  82. package/generators/h5-react/templates/packages/eslint/eslint.config.react.ts +33 -0
  83. package/generators/h5-react/templates/packages/eslint/package.json +22 -0
  84. package/generators/h5-react/templates/packages/js-bridge/eslint.config.ts +17 -0
  85. package/generators/h5-react/templates/packages/js-bridge/package.json +23 -0
  86. package/generators/h5-react/templates/packages/js-bridge/src/call.ts +126 -0
  87. package/generators/h5-react/templates/packages/js-bridge/src/closeH5Page.ts +9 -0
  88. package/generators/h5-react/templates/packages/js-bridge/src/getUserInfo.ts +96 -0
  89. package/generators/h5-react/templates/packages/js-bridge/src/index.ts +15 -0
  90. package/generators/h5-react/templates/packages/js-bridge/tsconfig.json +3 -0
  91. package/generators/h5-react/templates/packages/js-bridge/type.d.ts +24 -0
  92. package/generators/h5-react/templates/packages/request/axios.d.ts +42 -0
  93. package/generators/h5-react/templates/packages/request/eslint.config.ts +17 -0
  94. package/generators/h5-react/templates/packages/request/package.json +22 -0
  95. package/generators/h5-react/templates/packages/request/src/index.ts +165 -0
  96. package/generators/h5-react/templates/packages/request/src/interceptors.ts +126 -0
  97. package/generators/h5-react/templates/packages/request/src/types.ts +101 -0
  98. package/generators/h5-react/templates/packages/request/src/url-resolver.ts +66 -0
  99. package/generators/h5-react/templates/packages/request/src/utils.ts +12 -0
  100. package/generators/h5-react/templates/packages/request/tsconfig.json +3 -0
  101. package/generators/h5-react/templates/packages/request/umi.d.ts +94 -0
  102. package/generators/h5-react/templates/packages/typescript/package.json +11 -0
  103. package/generators/h5-react/templates/packages/typescript/tsconfig.base.json +23 -0
  104. package/generators/h5-react/templates/packages/typescript/tsconfig.react.json +7 -0
  105. package/generators/h5-react/templates/packages/umi-config/eslint.config.ts +12 -0
  106. package/generators/h5-react/templates/packages/umi-config/package.json +31 -0
  107. package/generators/h5-react/templates/packages/umi-config/src/config.dev.ts +34 -0
  108. package/generators/h5-react/templates/packages/umi-config/src/config.prod.development.ts +17 -0
  109. package/generators/h5-react/templates/packages/umi-config/src/config.prod.production.ts +42 -0
  110. package/generators/h5-react/templates/packages/umi-config/src/config.prod.testing.ts +17 -0
  111. package/generators/h5-react/templates/packages/umi-config/src/config.prod.ts +56 -0
  112. package/generators/h5-react/templates/packages/umi-config/src/config.ts +86 -0
  113. package/generators/h5-react/templates/packages/umi-config/src/index.ts +25 -0
  114. package/generators/h5-react/templates/packages/umi-config/src/plugins/apply-sentry-plugin.ts +57 -0
  115. package/generators/h5-react/templates/packages/umi-config/src/type.d.ts +3 -0
  116. package/generators/h5-react/templates/packages/umi-config/tsconfig.json +3 -0
  117. package/generators/h5-react/templates/packages/utils/eslint.config.ts +12 -0
  118. package/generators/h5-react/templates/packages/utils/package.json +27 -0
  119. package/generators/h5-react/templates/packages/utils/src/date.ts +21 -0
  120. package/generators/h5-react/templates/packages/utils/src/env.ts +40 -0
  121. package/generators/h5-react/templates/packages/utils/src/index.ts +3 -0
  122. package/generators/h5-react/templates/packages/utils/src/md5.ts +17 -0
  123. package/generators/h5-react/templates/packages/utils/src/mock.ts +83 -0
  124. package/generators/h5-react/templates/packages/utils/src/number.ts +23 -0
  125. package/generators/h5-react/templates/packages/utils/src/tailwind.ts +12 -0
  126. package/generators/h5-react/templates/packages/utils/src/url.ts +19 -0
  127. package/generators/h5-react/templates/packages/utils/tsconfig.json +9 -0
  128. package/generators/h5-react/templates/page.config.ts +1 -0
  129. package/generators/h5-react/templates/pnpm-workspace.yaml +17 -0
  130. package/generators/h5-react/templates/scripts/collect-dist.js +78 -0
  131. package/generators/h5-react/templates/scripts/dev-preset.js +265 -0
  132. package/generators/h5-react/templates/scripts/dev-preset.schema.json +39 -0
  133. package/generators/h5-react/templates/scripts/dev.js +133 -0
  134. package/generators/h5-react/templates/scripts/gateway.ts +241 -0
  135. package/generators/h5-react/templates/turbo.json +86 -0
  136. package/generators/subapp-h5/ignore-list.json +1 -0
  137. package/generators/subapp-h5/index.js +424 -0
  138. package/generators/subapp-h5/meta.json +10 -0
  139. package/generators/subapp-h5/templates/.env +1 -0
  140. package/generators/subapp-h5/templates/.stylelintrc.js +22 -0
  141. package/generators/subapp-h5/templates/config/config.dev.ts +7 -0
  142. package/generators/subapp-h5/templates/config/config.prod.development.ts +7 -0
  143. package/generators/subapp-h5/templates/config/config.prod.production.ts +10 -0
  144. package/generators/subapp-h5/templates/config/config.prod.testing.ts +7 -0
  145. package/generators/subapp-h5/templates/config/config.prod.ts +7 -0
  146. package/generators/subapp-h5/templates/config/config.ts +6 -0
  147. package/generators/subapp-h5/templates/config/routes.ts +13 -0
  148. package/generators/subapp-h5/templates/eslint.config.ts +12 -0
  149. package/generators/subapp-h5/templates/mock/user.ts +34 -0
  150. package/generators/subapp-h5/templates/package.json +42 -0
  151. package/generators/subapp-h5/templates/src/app.tsx +14 -0
  152. package/generators/subapp-h5/templates/src/assets/yay.jpg +0 -0
  153. package/generators/subapp-h5/templates/src/intl.ts +37 -0
  154. package/generators/subapp-h5/templates/src/layouts/index.tsx +10 -0
  155. package/generators/subapp-h5/templates/src/pages/index.tsx +22 -0
  156. package/generators/subapp-h5/templates/src/services/user.ts +38 -0
  157. package/generators/subapp-h5/templates/tailwind.config.js +16 -0
  158. package/generators/subapp-h5/templates/tailwind.css +7 -0
  159. package/generators/subapp-h5/templates/tsconfig.json +3 -0
  160. package/generators/subapp-h5/templates/typings.d.ts +1 -0
  161. package/lib/setup-multica-desktop.js +154 -0
  162. package/package.json +1 -1
@@ -0,0 +1,64 @@
1
+ ---
2
+ description: <%= ProjectName %>(<%= projectName %>)Monorepo:结构、网关、dev 预设、workspace 与子应用扩展方式
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # <%= ProjectName %> Monorepo 上下文
7
+
8
+ ## 脚手架与多子应用
9
+
10
+ - 仓库由 **`mico create h5-react`** 初始化:会生成 monorepo 基座,并**联动** **`mico create subapp-h5`** 在 `apps/<名>/` 下创建**首个**子应用(不在 h5-react 模板中重复维护子应用目录)。
11
+ - 之后在**仓库根目录**可**多次**执行 **`mico create subapp-h5`**,按需增加更多 Umi 子应用;每次会更新根目录 **`page.config.ts`**、**`dev.preset.json`**(`full.apps`)等(由生成器写入,无需手抄模板路径)。
12
+ - 子应用目录名建议使用 **kebab-case**;本模板约定 **`apps/<目录名>/package.json` 的 `name` 与目录名一致**,以便 `pnpm dev:preset` 的校验与 `pnpm --filter` 一致。
13
+
14
+ ## 布局
15
+
16
+ | 路径 | 说明 |
17
+ |------|------|
18
+ | `apps/*` | 可运行 **Umi 4** 应用;**目录名** = 网关 `page.config.ts` 的**键**;`package.json` 的 `name` 建议与目录名一致,且与 `dev.preset.json` 里 `presets.*.apps` 条目一致 |
19
+ | `packages/*` | 内部包,**当前包含**:`<%= packageScope %>/eslint`、`<%= packageScope %>/typescript`、`<%= packageScope %>/utils`、`<%= packageScope %>/domain`、`<%= packageScope %>/js-bridge`、`<%= packageScope %>/request`、`<%= packageScope %>/common-intl`、`<%= packageScope %>/components`、`<%= packageScope %>/constant`、`<%= packageScope %>/deeplink`、`<%= packageScope %>/umi-config`(详见 **`.cursor/rules/internal-packages.mdc`**) |
20
+ | `page.config.ts` | 网关要启动哪些应用:**键** = `apps/` 下文件夹名 |
21
+ | `.env` / `.env.development` / `.env.testing` / `.env.production` | **仓库根目录**集中维护的环境变量(`UMI_APP_API_BASE_URL`、`UMI_APP_CDN_BASE_URL`、`UMI_APP_LANG_BASE_URL`、`UMI_APP_ENV` 等);由根 `package.json` 的 `dotenv-cli` 链按 `pnpm dev:gateway` / `pnpm build:*` 等加载,并通过 Umi `define` / `process.env.*` 透到子应用。**不要**在子应用里重复维护 |
22
+ | `.lintstagedrc.js` | **根目录集中维护**的 lint-staged 配置(`apps/*`、`packages/!(eslint)`),见 **`.cursor/rules/git-hooks.mdc`**;**已不再**在每个 `packages/<x>/` 下放 `.lintstagedrc` |
23
+ | `scripts/dev.js` | 根目录 **`pnpm dev`**:扫描 `apps/` 下含 `dev` 脚本的子应用,**仅启动其中一个**(单应用直启、多应用终端选序号);经 **dotenv-cli** + `pnpm --filter` 拉起,**不**走 Turborepo |
24
+ | `scripts/gateway.ts` | 开发网关:读 `page.config.ts`,起子应用 + 反向代理(子应用端口自 4000 起探测,网关约 3000 起);子进程 **stderr** 常含 Tailwind watch、打包器等的**进度日志**(非错误),脚本以普通样式输出,勿与崩溃混为一谈 |
25
+ | `scripts/collect-dist.js` | `pnpm build` / `pnpm build:*` / `pnpm test` 在 **turbo 成功后**执行:把各 `apps/<名>/dist` **移动**到根目录 `dist/<名>/`,并删 `.map`(根 `dist/` 在 `.gitignore`) |
26
+ | `scripts/dev-preset.js` / `dev-preset.schema.json` | `pnpm dev:preset` 的实现与 schema |
27
+ | `dev.preset.json` | `pnpm dev:preset` 的预设;`presets.full.apps` 由 **`mico create subapp-h5`** 自动追加 |
28
+ | `CICD/` | Jenkins 脚本:`CDN_PUBLIC_PATH`、网宿刷新等;创建项目时按 **CDN path prefix**(可选)生成路径(见 **`.cursor/rules/cicd-deploy.mdc`**) |
29
+
30
+ > **Sentry sourcemap 插件已迁移**到 **`packages/umi-config/src/plugins/apply-sentry-plugin.ts`**,由 **`createProductionConfig`** 内部调用;仓库根 `scripts/` 已不再持有 `apply-sentry-plugin.ts`。详见 **`.cursor/rules/umi-config.mdc`**。
31
+
32
+ ## 根目录常用命令
33
+
34
+ - `pnpm dev:gateway`:网关(单端口;访问子应用路径 `/{apps 下文件夹名}`)
35
+ - `pnpm dev:preset` / `pnpm list:preset`:按预设**并行启动指定应用**(**无**网关);预设里 `apps` 填各子应用 **`package.json` 的 `name`**(本仓库与目录名一致;`dev-preset.js` 校验时与 `apps/` **目录名**列表对齐,二者一致即可)
36
+ - `pnpm dev`:运行 **`scripts/dev.js`**,**只启动一个**子应用(交互或自动),**不是** `turbo run dev`
37
+ - `pnpm build` / `pnpm build:development` / `pnpm build:testing` / `pnpm build:production` / `pnpm lint` / `pnpm lint:fix`:**Turborepo** 按 `turbo.json` 调度;`build*` 的根脚本经 **dotenv-cli** 加载对应环境的 `.env*` 链(见根 `package.json`);可选 **`TURBO_FILTER`** 环境变量限定子包,与 CICD `before_build.sh` 一致
38
+ - `pnpm lint-staged`:**直接调用 `lint-staged`**(读取根 `.lintstagedrc.js`),**不**经过 Turborepo
39
+ - `pnpm build` / `pnpm build:*` / `pnpm test`:turbo 阶段结束后还会跑 **`collect-dist.js`**
40
+ - `pnpm test`:需 `turbo.json` 声明 **`test`** 任务且各包有 **`test` 脚本**,否则根命令会失败
41
+ - 单包开发:`cd apps/<目录> && pnpm dev`
42
+
43
+ ## Workspace 与版本
44
+
45
+ - 范围:`pnpm-workspace.yaml` 的 `apps/*`、`packages/*`
46
+ - 共享版本:**pnpm catalog**(`umi`、`react`、`react-dom`、`@types/react*`、`tailwindcss`、`tailwindcss-safe-area`、`@umijs/plugins`、`eslint`、`stylelint`、`cross-env`、`@common-web/sentry`);子包写 `catalog:`,勿在应用里单独钉死版本(除非有意覆盖)
47
+ - 根 `package.json`:`name` 为 **`<%= projectName %>`**(私有 monorepo);`pnpm.overrides` 已固定 `eslint: catalog:` 与 `jiti: ^2`,并通过 `peerDependencyRules.allowedVersions` 放行 `eslint@9` / `react@18`
48
+ - **`@sentry/webpack-plugin`** 安装在 **`packages/umi-config`** 的 `devDependencies` 中(不是仓库根),因为 Sentry 上传逻辑由本包封装
49
+
50
+ ## 环境
51
+
52
+ - Node:建议 **22 LTS+**
53
+ - pnpm:与根 **`packageManager`** 一致(当前 **pnpm@10.18.2**)
54
+
55
+ ## 新增应用或包
56
+
57
+ - 优先使用 **`mico create subapp-h5`**(在 monorepo 根目录执行),由生成器创建 `apps/<名>/` 并维护 `page.config.ts` / `dev.preset.json`。
58
+ - 手工新增时:目录须落在 workspace glob 内;**走网关**时在 `page.config.ts` 加键(**文件夹名**);**走 dev 预设**时在 `dev.preset.json` 的 `apps` 里加对应 **`package.json` 的 `name`**。
59
+ - 构建后若需本地 `apps/<名>/dist`,根目录 `pnpm build` 后可能被 `collect-dist` 移走,需在该应用下再执行 `pnpm build` 才会重新出现。
60
+
61
+ ## 文档与规则
62
+
63
+ - 人读:**`README.md`**、**`packages/common-intl/README.md`** 等。
64
+ - 协作/编辑器:**`.cursor/rules/`**(如 **`umi-app`**、**`umi-config`**、**`umi-mock`**、**`workspace-request`**、**`common-intl`**、**`tailwind-umi`**、**`internal-packages`**、**`package-json`**、**`git-hooks`**、**`cicd-deploy`**)与实现对照,避免 Mock 路径、请求 URL、`init()` / 国际化行为、子应用 Umi 配置等与项目实际不一致。
@@ -0,0 +1,52 @@
1
+ ---
2
+ description: pnpm workspace 下 package.json 依赖、脚本与 catalog 约定
3
+ globs: "**/package.json"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # package.json 约定
8
+
9
+ ## 内部包引用
10
+
11
+ - 引用本仓库包使用 **`workspace:^`**(例如 `"<%= packageScope %>/eslint": "workspace:^"`)
12
+ - 内部包命名空间:**`<%= packageScope %>/*`**,当前包含:
13
+ - 工具与基线:**`eslint`**、**`typescript`**、**`utils`**
14
+ - 运行时基础:**`domain`**、**`js-bridge`**、**`request`**、**`common-intl`**
15
+ - UI 与业务复用:**`components`**、**`constant`**、**`deeplink`**
16
+ - 子应用配置工厂:**`umi-config`**(封装 `createBaseConfig` / `createProConfig` / `createProductionConfig` / Sentry 上传插件等)
17
+ - **Umi 子应用** 默认依赖:`common-intl`、`components`、`constant`、`deeplink`、`domain`、`js-bridge`、`request`、`umi-config`、`utils`(与 **`mico create subapp-h5`** 模板一致)
18
+
19
+ ## Catalog 依赖
20
+
21
+ 下列依赖在子包/子应用中应使用 **`catalog:`**(版本只在 `pnpm-workspace.yaml` 的 `catalog` 中维护):
22
+
23
+ - `umi`、`react`、`react-dom`
24
+ - `@types/react`、`@types/react-dom`
25
+ - `tailwindcss`、`tailwindcss-safe-area`、`@umijs/plugins`(Umi 子应用接入 Tailwind 时)
26
+ - `eslint`、`stylelint`(根与各包按需)
27
+ - `cross-env`(子应用 `build:*` 用来注入 `UMI_ENV`)
28
+ - `@common-web/sentry`(子应用 Sentry 运行时与错误边界)
29
+
30
+ ```json
31
+ // ✅ 符合约定
32
+ "umi": "catalog:",
33
+ "tailwindcss-safe-area": "catalog:"
34
+
35
+ // ❌ 避免在 apps/packages 里单独钉死版本(除非有意覆盖 catalog)
36
+ "umi": "4.4.12"
37
+ ```
38
+
39
+ > **`@sentry/webpack-plugin`** 安装在 **`packages/umi-config`** 的 `devDependencies`(用作 Sentry sourcemap 上传),**不**在仓库根、也**不**在子应用中重复声明。
40
+
41
+ ## 根脚本模式
42
+
43
+ - 根目录通过 **`turbo run <task>`** 聚合 workspace(**例外**:根 **`pnpm dev`** 为 **`node scripts/dev.js`**,交互式只启**一个**子应用,不经过 Turborepo)。
44
+ - 根 `pnpm build` / `build:development` / `build:testing` / `build:production` 经 **dotenv-cli** 加载对应 `.env` 链后调用 turbo,成功后执行 **`node scripts/collect-dist.js`**;`TURBO_FILTER` 可选,用于按子包过滤构建(与 CICD `before_build.sh` 一致)。
45
+ - 子包需在 `package.json` 中声明对应 `scripts`(如 `dev`、`build`、`build:development`、`build:testing`、`build:production`、`lint`、`lint:fix`),且 `turbo.json` 的 `tasks` 中要有该任务名才会被调度。
46
+ - **`packages/components`** 与 **`packages/umi-config`** 因含 Umi 类型,`scripts.postinstall` / `scripts.setup` 调 **`umi setup`** 生成 `src/.umi/tsconfig.json`;其他纯 TS 包不需要。
47
+ - **lint-staged**:根目录 `lint-staged` 脚本直接调 **`lint-staged`**(读 **`.lintstagedrc.js`**);子包**无需**再写 `.lintstagedrc`,详见 **`.cursor/rules/git-hooks.mdc`**。
48
+
49
+ ## dev 预设(`dev.preset.json`)
50
+
51
+ - `presets.<名>.apps` 中的字符串须与 **`apps/<某目录>/package.json` 的 `name`** 一致(本模板下通常与**目录名**相同),不是随意别名
52
+ - 修改预设后无需改网关;`dev:preset` 与 `dev:gateway` 相互独立
@@ -0,0 +1,60 @@
1
+ ---
2
+ description: Umi 4 子应用通过 @umijs/plugins 接入 Tailwind CSS 3 + tailwindcss-safe-area 的约定
3
+ globs: apps/**/config/config.ts,apps/**/tailwind.css,apps/**/tailwind.config.js
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Tailwind CSS(Umi `apps/*`)
8
+
9
+ ## 依赖
10
+
11
+ - 在子应用 `package.json` 中声明 **`tailwindcss`**、**`@umijs/plugins`**、**`tailwindcss-safe-area`**(均使用 **`catalog:`**),版本由根 **`pnpm-workspace.yaml` 的 `catalog`** 维护。
12
+ - 优先 **Tailwind 3**:与官方插件基于 CLI + `tailwind.config.js` 的流程一致;v4 需自行验证兼容性。
13
+
14
+ ## Umi 配置(由 `<%= packageScope %>/umi-config` 工厂注入)
15
+
16
+ - **`createBaseConfig`** 已默认在子应用 `config/config.ts` 中启用:
17
+
18
+ ```ts
19
+ plugins: ["@umijs/plugins/dist/tailwindcss", "@umijs/plugins/dist/request"],
20
+ tailwindcss: {},
21
+ request: {},
22
+ ```
23
+
24
+ - 子应用**不需要**在 `config.ts` 中再次声明 `plugins` / `tailwindcss`;如要扩展(如 PurgeCSS 选项)通过 `createBaseConfig({ ...customDelta })` 透传。
25
+ - 同时 `createBaseConfig` 已配置 **`postcss-pxtorem`**(`rootValue: 16`、`propList: ['*']`、`minPixelValue: 2`),与 `tailwind.css` 中的 `1vw` 字号兼容;这是 H5 适配的项目级约定,**不要**在子应用里关闭。
26
+
27
+ ## 应用根目录(与 `config/` 同级)
28
+
29
+ | 文件 | 说明 |
30
+ |------|------|
31
+ | `tailwind.css` | 入口;插件**固定**读取该文件名;含 `@tailwind base/components/utilities`,并设置 `html { font-size: 16px; }` 与 `1vw` 适配(与 `postcss-pxtorem` 配合做 H5 字号缩放) |
32
+ | `tailwind.config.js` | 插件**固定**读取该文件名(非 `.ts`);`content` 必须覆盖:`./src/**/*.{js,jsx,ts,tsx,less,css}`、`!./src/.umi/**`、`!./src/.umi-production/**`,并扫描共享 UI 包 **`../../packages/components/src/**/*.{ts,tsx}`**;`plugins` 必须包含 **`tailwindcss-safe-area`**(提供 `pt-safe`、`pb-safe-or-4`、`px-safe` 等安全区工具类) |
33
+
34
+ ```js
35
+ // tailwind.config.js(subapp-h5 默认模板)
36
+ import safeAreaConfig from "tailwindcss-safe-area"
37
+
38
+ export default {
39
+ content: [
40
+ "./src/**/*.{js,jsx,ts,tsx,less,css}",
41
+ "!./src/.umi/**",
42
+ "!./src/.umi-production/**",
43
+ "./README.md",
44
+ "./docs/**/*.{md,mdx}",
45
+ "../../packages/components/src/**/*.{ts,tsx}",
46
+ ],
47
+ plugins: [safeAreaConfig],
48
+ }
49
+ ```
50
+
51
+ ## 与 `<%= packageScope %>/components` 的配合
52
+
53
+ - **`packages/components`** 中的布局组件(`Layout` / `ImmersiveHeader` / `LayoutFooter`)使用 `pt-safe` / `pb-safe-or-4` 等类名,依赖子应用 `tailwind.config.js` 把该包源码加入 `content`;**未加入会导致样式被 Tree-shake 掉**。
54
+ - 新增其他被业务复用的内部包,且其源码包含 Tailwind class 时,需把对应路径一并追加到子应用的 `content`。
55
+
56
+ ## 说明
57
+
58
+ - `@umijs/plugins` 为 Umi 官方扩展插件包;Tailwind 能力在 **`dist/tailwindcss`**,不在默认 `umi` 包内自动启用。
59
+ - 插件会生成并注入样式,一般无需在业务中手动 `import` 根目录 `tailwind.css`。
60
+ - **样板**:由 **`mico create subapp-h5`** 生成的 **`apps/<子应用目录>/`** 默认已包含上述依赖与文件,可直接对照;手工接入或旧应用补全时按上表补齐。
@@ -0,0 +1,74 @@
1
+ ---
2
+ description: apps 下 Umi 4 应用的 ESLint、Stylelint、TypeScript 与 workspace 包用法
3
+ globs: "apps/**/*.{ts,tsx,mjs,js,jsx}"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Umi 应用层约定(`apps/*`)
8
+
9
+ ## TypeScript
10
+
11
+ - `tsconfig.json` 仅 **extends** Umi 生成的 **`./src/.umi/tsconfig.json`**(首次需 `umi setup` / `pnpm dev` 生成);**`@/*`**、**`@@/*`** 等路径别名由 Umi 生成的 tsconfig 提供。若类型解析报错,执行 `pnpm dev` 或 `umi setup` 让 Umi 重新生成 `src/.umi/tsconfig.json`
12
+
13
+ ```json
14
+ {
15
+ "extends": "./src/.umi/tsconfig.json"
16
+ }
17
+ ```
18
+
19
+ - 如需统一基线,可再引入 `<%= packageScope %>/typescript` 的导出(以包实际导出为准)
20
+
21
+ ## Mock(开发)
22
+
23
+ - 约定见 **`.cursor/rules/umi-mock.mdc`**(**`defineMock`**、校验、可选远程透传、与 **`src/services/`** 下导出的类型对齐)
24
+
25
+ ## ESLint(flat config)
26
+
27
+ - 应用根目录使用 **`eslint.config.ts`**(ESLint **9**),`import` **`<%= packageScope %>/eslint/react`**,用 **`defineConfig`** 展开并设置 **`parserOptions.tsconfigRootDir: import.meta.dirname`**(见 **`mico create subapp-h5`** 模板)
28
+ - **`<%= packageScope %>/eslint`**:`package.json` 的 **`exports`** 中 **`.`** 为基础 TS + Prettier;**`./react`** 在 base 上叠加 React / Hooks / Refresh,并忽略 **`src/.umi*`**
29
+ - `lint` 脚本为 **`eslint`**(及 stylelint),非 `umi lint` 的 legacy ESLint 流程
30
+
31
+ ## Stylelint
32
+
33
+ - 使用 **`.stylelintrc.js`**,继承 **`umi/stylelint`**,否则子应用 **`lint`** 中的 stylelint 可能报错
34
+
35
+ ## 共享代码
36
+
37
+ - 通用工具从 **`<%= packageScope %>/utils`** 引用;子路径以该包 **`exports`** 为准(`./tailwind`、`./env`、`./url`、`./number`、`./date`、`./mock` 等)
38
+ - **`<%= packageScope %>/domain`**:基址与运行时配置(**`apiBaseUrl`**、**`cdnBaseUrl`**、**`langBaseUrl`**);由 **`request`**、**`common-intl`**、**`js-bridge`** 使用
39
+ - **`<%= packageScope %>/js-bridge`**:H5 与原生通信能力(**`canUseJSBridge`** / **`callJSBridgeMethods`** / **`getUserInfo`** / **`closeH5Page`** 等);详见 **`.cursor/rules/internal-packages.mdc`**
40
+ - **`<%= packageScope %>/request`**:统一 HTTP **`request(url, options)`**(`workspace:^`);相对路径会经 **`domain`** 与 **`url-resolver`** 拼接。与 **`@umijs/plugins/dist/request`**、`createBaseConfig` 中的 **`request: {}`** 配套。细节见 **`.cursor/rules/workspace-request.mdc`**
41
+ - **`<%= packageScope %>/components`**:项目级布局/UI(**`Layout`**、**`ImmersiveHeader`**、**`LayoutFooter`** 等);按 **`./Layout`** 等子路径 import,**`tailwind.config.js`** 的 `content` 已扫描该包源码(见 **`.cursor/rules/tailwind-umi.mdc`**)
42
+ - **`<%= packageScope %>/constant`** / **`<%= packageScope %>/deeplink`**:业务常量与客户端跳转占位实现,按业务域扩展
43
+ - 国际化:**`subapp-h5`** 模板在 **`src/intl.ts`** 中使用 **`init()`**(`<%= packageScope %>/common-intl` 预配置封装)取得 `{ fetchMultilingualData, i18n }`,再用 **`addIntl({ ... }, i18n)`** 定义文案对象;**`src/app.tsx`** 只负责首屏前 **`fetchMultilingualData()`**;组件 **`import intl from '@/intl'`**。包级说明见 **`packages/common-intl/README.md`** 与 **`.cursor/rules/common-intl.mdc`**
44
+ - 错误监控:子应用通过 **`@common-web/sentry`**(**`catalog:`**)在 **`src/layouts/index.tsx`** 使用 **`SentryErrorBoundary`** 包裹 **`Outlet`**;生产构建的 sourcemap 上传由 **`<%= packageScope %>/umi-config`** 的 `createProductionConfig` 自动注入(**子应用不再**手写 `applySentryPlugin`)
45
+ - 改共享 ESLint / TS / 请求封装 / i18n / 配置工厂:编辑 **`packages/eslint`**、**`packages/typescript`**、**`packages/domain`**、**`packages/request`**、**`packages/common-intl`**、**`packages/umi-config`** 等;应用侧以 **`@/intl`**、**`workspace` 包名** 等约定入口为准
46
+
47
+ ## Umi 配置目录(委托给 `umi-config` 工厂)
48
+
49
+ - 子应用 **`config/`** 下的所有配置文件都**只 `import` `<%= packageScope %>/umi-config` 的工厂**并把业务自定义 delta 作为**第二参数**传入,避免在子应用里重抄基础字段:
50
+ - **`config/config.ts`** → `createBaseConfig({ routes })`(基础公共配置 + 路由)
51
+ - **`config/config.dev.ts`** → `createDevConfig({ /* dev delta */ })`
52
+ - **`config/config.prod.ts`** → `createProConfig({ /* build delta */ })`(**单参**:构建公共 delta;不再需要 `appName`)
53
+ - **`config/config.prod.development.ts`** → `createDevelopmentConfig({ ... })`
54
+ - **`config/config.prod.testing.ts`** → `createTestingConfig({ ... })`
55
+ - **`config/config.prod.production.ts`** → `createProductionConfig({ appName }, { ... })`(自动接入 Sentry,`appName` 用于 sourcemap `urlPrefix`)
56
+ - 文件名与 Umi 加载顺序约定一致(`config.ts` < `config.[UMI_ENV].ts` < `config.[dev|prod].ts` < `config.[dev|prod].[UMI_ENV].ts`);与 `package.json` 中 **`UMI_ENV`**(`development` / `testing` / `production`)及构建脚本对齐。
57
+ - 完整设计与 Sentry 接入(含 `createProductionConfig` 的 `appName` 用途)见 **`.cursor/rules/umi-config.mdc`**。
58
+
59
+ ## 路由
60
+
61
+ - **`config/routes.ts`**:模板内只配置**静态**基础路由(如首页);注释约定动态路由可从 **`window.__MICO_MENUS__`** 等获取,由业务接入。
62
+ - 路由历史由 `createBaseConfig` 默认 **`history: { type: "hash" }`**;Umi 会自动使用 **`src/layouts/index.tsx`** 作为全局布局,路由表里一般不必再写 layout 组件。
63
+
64
+ ## 生产构建关键点(由 `umi-config` 工厂注入,了解即可)
65
+
66
+ - **`publicPath: 'auto'`** + **`cssPublicPath: './'`**:`createProConfig` **不再消费 `CDN_PUBLIC_PATH` / `appName`**;JS publicPath 由 webpack 在运行时按 HTML 加载位置解析,CSS `url()` 走相对路径。该写法与 qiankun slave 默认开启的 `runtimePublicPath` 不冲突,并允许产物放到任意 CDN 子目录下。
67
+ - **`devtool: 'hidden-source-map'`**:仅 `createProductionConfig` 开启,产出 `.map` 供 Sentry 上传。
68
+ - **`chainWebpack`**:`createProConfig` 关 `runtimeChunk`(把 runtime 内联进入口 `umi.js`)、删 `runtimePublicPath` 插件、把异步 chunk 命名为 `[name].[contenthash:8].async.js`(**不再** `splitChunks(false)`,保留动态 `import()` 按需加载能力);`createProductionConfig` 再叠加 `applySentryPlugin({ memo, appName })`(`appName` 仅落到 Sentry **`urlPrefix`**,需 **`SENTRY_AUTH_TOKEN`**)。详见 **`.cursor/rules/umi-config.mdc`** 的「构建期代码分割策略」。
69
+ - **`externals`**:默认声明 **`react`**、**`react-dom`**、**`@common-web/sentry`**;启用时须与页面/主应用注入的全局变量一致(如 **`React` / `ReactDOM` / `CommonWebSentry`**)。
70
+ - 业务确实需要覆盖时,把 delta 传给工厂的第二个参数即可(`chainWebpack` 会**叠加**调用,不会丢失工厂内置逻辑)。
71
+
72
+ ## Tailwind CSS
73
+
74
+ - **`subapp-h5` 模板默认已接入** Tailwind 3 + **`tailwindcss-safe-area`**;插件由 `createBaseConfig` 内置(`@umijs/plugins/dist/tailwindcss`),子应用只需提供 **`tailwind.css`** / **`tailwind.config.js`**。细节与手工接入步骤见 **`.cursor/rules/tailwind-umi.mdc`**。
@@ -0,0 +1,86 @@
1
+ ---
2
+ description: <%= packageScope %>/umi-config 子应用 Umi 配置工厂(基础 + 环境 delta)与 Sentry 接入
3
+ globs: "{apps/**/config/**/*.ts,packages/umi-config/**/*.{ts,tsx}}"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # `<%= packageScope %>/umi-config`(`packages/umi-config`)
8
+
9
+ 子应用 **`config/`** 目录下的所有 Umi 配置都委托给本包的工厂函数生成;本包同时托管 **Sentry sourcemap 上传插件**(**已不再放在仓库根 `scripts/`**)。
10
+
11
+ ## 设计:基础 + 环境 delta
12
+
13
+ Umi 在加载 **`config/`** 时按文件名约定**叠加合并**:
14
+ `config.ts` < `config.[UMI_ENV].ts` < `config.[dev|prod].ts` < `config.[dev|prod].[UMI_ENV].ts`
15
+
16
+ 因此本包按 **6 个工厂彼此无继承** 的方式拆分;每个工厂只产出当前文件该负责的 delta:
17
+
18
+ | 工厂导出 | 目标文件 | 职责(delta) |
19
+ |---------|---------|----------------|
20
+ | `createBaseConfig` | `config/config.ts` | 全部公共字段:`mountElementId`、`history`、Tailwind / request 插件、`monorepoRedirect`、`postcss-pxtorem` 等(**不**显式声明 `codeSplitting`,沿用 Umi 默认 `bigVendors` 策略) |
21
+ | `createDevConfig` | `config/config.dev.ts` | `umi dev` 阶段 delta(默认 `/api` 代理) |
22
+ | `createProConfig` | `config/config.prod.ts` | 构建阶段公共 delta:**`publicPath: 'auto'`** + **`cssPublicPath: './'`**(webpack 运行时按 HTML 加载位置解析,CSS `url()` 相对路径,避开 qiankun 默认开启的 `runtimePublicPath` 冲突)、**`externals`**(react / react-dom / @common-web/sentry)、`chainWebpack`:`runtimeChunk(false)` 把 webpack runtime 内联进入口 `umi.js`、删除 `runtimePublicPath` 插件、把异步 chunk 命名为 `[name].[contenthash:8].async.js` |
23
+ | `createDevelopmentConfig` | `config/config.prod.development.ts` | `UMI_ENV=development` 构建 delta(保留扩展点,默认空) |
24
+ | `createTestingConfig` | `config/config.prod.testing.ts` | `UMI_ENV=testing` 构建 delta(保留扩展点,默认空) |
25
+ | `createProductionConfig` | `config/config.prod.production.ts` | `UMI_ENV=production` 构建 delta:`devtool: 'hidden-source-map'` + 复用 `createProConfig` 的 `chainWebpack`(`runtimeChunk(false)` / 删 `runtimePublicPath` / `chunkFilename`)+ 通过 `applySentryPlugin` 上传 Source Map |
26
+
27
+ > 子应用模板生成的每个 `config/*.ts` 都极简(只 `import` 工厂并传必要参数),原则上**不要**在子应用里重抄 `mountElementId` / `externals` 等公共字段,需要项目级共享的改动直接改本包。
28
+
29
+ ## 子应用使用示例(`subapp-h5` 默认模板)
30
+
31
+ ```ts
32
+ // config/config.ts
33
+ import { createBaseConfig } from '<%= packageScope %>/umi-config/config';
34
+ import routes from './routes';
35
+ export default createBaseConfig({ routes });
36
+
37
+ // config/config.prod.ts
38
+ import { createProConfig } from '<%= packageScope %>/umi-config/config.prod';
39
+ export default createProConfig({ /* custom delta */ });
40
+
41
+ // config/config.prod.production.ts
42
+ import { createProductionConfig } from '<%= packageScope %>/umi-config/config.prod.production';
43
+ export default createProductionConfig({ appName: '<子应用 package.json name>' }, { /* custom delta */ });
44
+ ```
45
+
46
+ - **`createProductionConfig`** 的 **`appName`** 需与 **`apps/<目录>/package.json` 的 `name`** 一致,仅用于 Sentry **`urlPrefix`** 段。
47
+ - **`createProConfig`** 已不再依赖 `appName` / `CDN_PUBLIC_PATH`:固定输出 **`publicPath: 'auto'`** + **`cssPublicPath: './'`**,由 webpack 与 mini-css-extract loader 在运行时按 HTML 加载位置解析。这样产物可以放到任意 CDN 子目录,并避免与 qiankun slave 默认开启的 `runtimePublicPath` 冲突。
48
+ - 业务自定义 delta 始终是工厂的**最后一个参数**(`createProConfig` 单参,`createProductionConfig` 第二参),工厂内部用 **`{ ...defaults, ...options }`** 合并;想覆盖 `chainWebpack` / `externals` 时也从这里传。
49
+
50
+ ## 构建期代码分割策略(`createProConfig` / `createProductionConfig` 共享)
51
+
52
+ H5 子应用通过 SDK 注入 `<script>` 形式加载,宿主页只引一个入口 JS,但仍需要保留 **动态 `import()`** 的能力(按路由/按需加载图片库、富文本编辑器等)。工厂内的 `chainWebpack` 做了 3 件事:
53
+
54
+ 1. **`memo.optimization.runtimeChunk(false)`**:禁用独立的 runtime chunk,让 **webpack runtime 内联进入口 `umi.js`**——宿主页只需引一个入口 JS 即可启动。
55
+ 2. **`memo.plugins.delete('runtimePublicPath')`**:删掉 Umi 默认注入的 `RuntimePublicPathPlugin`,避免它在运行时用 `window.publicPath`(通常为空字符串)覆盖掉 `publicPath: 'auto'` 的解析结果。删除后异步 chunk 沿用 webpack 5 按 **`document.currentScript.src`** 推算出来的 publicPath,与入口 JS 同目录。
56
+ 3. **`memo.output.chunkFilename('[name].[contenthash:8].async.js')`**:给异步 chunk 一个稳定的命名格式(带 `.async.js` 后缀,便于在 CDN 日志 / Sentry 上识别非入口产物)。
57
+
58
+ **不要**再加 `memo.optimization.splitChunks(false)` 或 `babel-plugin-dynamic-import-node`:那种「打成一个文件」的策略会让 `import()` 退化成同步加载,丧失按需切片能力,仅适合极小的 SDK 场景。当前模板已统一切到「入口 JS + 异步 chunk」模式。
59
+
60
+ 需要进一步调整代码分割(例如把 `node_modules` 拆为独立 vendor)时,按以下顺序选择:
61
+
62
+ 1. 在 **`createBaseConfig`** 第二参里传 **`codeSplitting`**(Umi 顶层 API,最稳);
63
+ 2. 或在子应用 `config/config.prod.ts` 里通过 `chainWebpack` 进一步 `memo.optimization.splitChunks(...)` 叠加(工厂内 `chainWebpack` 会先于业务 `chainWebpack` 执行)。
64
+
65
+ ## 子路径导出
66
+
67
+ `package.json` 的 `exports` 对应每个工厂:`./config`、`./config.dev`、`./config.prod`、`./config.prod.development`、`./config.prod.testing`、`./config.prod.production`。**应用必须按子路径 import**,不要从根路径 `<%= packageScope %>/umi-config` 解构(保持构建时按需加载)。
68
+
69
+ ## Sentry sourcemap 插件(`src/plugins/apply-sentry-plugin.ts`)
70
+
71
+ - 仅由 **`createProductionConfig`** 内部调用;子应用**不再**直接 import 该模块。
72
+ - 使用 **Legacy Sourcemap 上传**(自托管 Sentry 不支持 Debug ID / Artifact Bundle)。
73
+ - `release.name` 与 `urlPrefix` 中的 **`version`** 来自仓库根 **`package.json` 的 `version`**(通过相对路径 import)。
74
+ - `urlPrefix` 形如 **`~/<%= cdnPrefixPath %><%= projectName %>/<version>/<appName>`**,与 CICD 写出的 `CDN_PUBLIC_PATH` 一致。
75
+ - 构建前需注入 **`SENTRY_AUTH_TOKEN`**(**`turbo.json` 的 `globalEnv`** 已声明)。
76
+ - `filesToDeleteAfterUpload: ['dist/**/*.map']` 上传成功后清理 `.map`,避免随 CDN 一起部署。
77
+
78
+ ## 包内 `umi setup`
79
+
80
+ - 本包 `package.json` 含 **`postinstall: umi setup`**(与 **`packages/components`** 一致),用于生成本包内 **`src/.umi/tsconfig.json`**,让本包源码(含 `defineConfig`、`umi/typings` 等类型)有完整 TS 支持。
81
+ - 不要把生成的 `.umi/` 目录提交。
82
+
83
+ ## 修改本包时的注意
84
+
85
+ - 改动 `createBaseConfig` 的字段 / `createProConfig` 的 `externals` 等会**同时影响所有子应用**:先在一个 `apps/<示例>/` 验证。
86
+ - `apply-sentry-plugin.ts` 中的 `org` / `url` / `<%= cdnPrefixPath %>` 已与 CICD、`<%= projectName %>` 绑定;如需换 Sentry 服务器或 CDN 前缀,**同时**改本文件、`<%= cdnPrefixPath %>` 模板与 CICD 脚本。
@@ -0,0 +1,80 @@
1
+ ---
2
+ description: Umi 子应用 mock/ 开发约定(defineMock、校验、可选远程透传)
3
+ globs: apps/**/mock/**/*.ts
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Umi 开发期 Mock(`apps/*`)
8
+
9
+ ## 职责边界
10
+
11
+ - Mock 仅用于**本地/开发**环境,与 Umi **`defineMock`** 生命周期一致;不要在生产逻辑里依赖 Mock 行为。
12
+ - 业务请求应走 **`<%= packageScope %>/request`**(或团队统一封装),Mock 中注册的 URL 形态须与 **`UMI_APP_API_BASE_URL`** 及 **`resolveRequestUrl`** 解析后的实际请求一致,否则对不上。
13
+
14
+ ## 与 `<%= packageScope %>/utils/mock` 的配合
15
+
16
+ - 公共逻辑集中在 **`<%= packageScope %>/utils/mock`**,子应用 **`mock/*.ts`** 只 `import` 复用,**不要**在每个 mock 文件里重抄:
17
+ - **`baseUrl`**:从 **`process.env.UMI_APP_API_BASE_URL`** 读取并去掉末尾 `/`,用作路由键前缀;保证与 **`<%= packageScope %>/request`** 的 `resolveRequestUrl` 拼接结果一致。
18
+ - **`tryProxy(req, res)`**:从 **`req.headers.referer`** 解析查询参数 **`remote`**,若是合法 `http(s):` URL,则用 `http-proxy` 透传到远程并返回 `true`;否则返回 `false` 让本地 mock 继续处理。`POST` 请求会自动写回 body。
19
+ - **`validateBody(body, schema, res)`**:对 **`req.body`** 跑 **zod `safeParse`**,校验失败时**自动**用 `res.status(400).json({ code, message })` 写回 4xx,并返回 `false`;校验通过返回 `true`。子应用 mock 用 **`if (!validateBody(req.body, schema, res)) return;`** 一行完成「入参校验 + 错误响应」,**不要**在每个文件里手抄 `safeParse` + 错误格式化。
20
+ - 典型 mock 文件结构:
21
+
22
+ ```ts
23
+ import { defineMock } from 'umi';
24
+ import { baseUrl, tryProxy, validateBody } from '<%= packageScope %>/utils/mock';
25
+ import { z } from 'zod';
26
+ import mockjs from 'mockjs';
27
+
28
+ export default defineMock({
29
+ [`POST ${baseUrl}/user`]: async (req, res) => {
30
+ const schema = z.object({ email: z.string() });
31
+ // 1. 入参校验:失败时 validateBody 已写回 400,这里 return 即可
32
+ if (!validateBody(req.body, schema, res)) return;
33
+ // 2. 可选远程透传
34
+ if (await tryProxy(req, res)) return;
35
+ // 3. 本地 Mock 响应
36
+ res.json(mockjs.mock({ /* ... */ }));
37
+ },
38
+ });
39
+ ```
40
+
41
+ ## `defineMock` 与路由键
42
+
43
+ - 使用 **`defineMock({ ... })`** 默认导出;**键**为「HTTP 方法 + 空格 + 路径」的字符串模板,路径部分用 **`baseUrl`** 拼接(如 ``[`POST ${baseUrl}/user`]``),与运行时实际请求一致。
44
+ - 同一文件内可注册多条路由;按业务域拆分多个模块文件时,保持每个文件职责单一,避免巨型单文件。
45
+
46
+ ## 入参校验
47
+
48
+ - **POST / PUT / PATCH** 等带 JSON(或表单)体的接口:优先使用 **`validateBody(req.body, schema, res)`**(来自 **`<%= packageScope %>/utils/mock`**),它会用 **zod `safeParse`** 校验失败时**自动**写回 `{ code: 400, message }`,调用方只需 `if (!validateBody(...)) return;`。
49
+ - **GET** 等以查询参数为主的接口:业务侧 **`request(..., { params })`** 会落到 URL **查询串**,Mock 侧应对 **`req.query`**(或与 Umi mock 提供的查询对象一致)做校验,**不要**只对 **`req.body`** 校验;如果 `validateBody` 不覆盖该场景,直接用 `schema.safeParse(req.query)` 并按相同 4xx 协议响应(也可后续把通用 query 校验沉淀到 `<%= packageScope %>/utils/mock`)。
50
+ - 校验失败时统一返回 **4xx** 与可读 **`message`**,与前端错误处理约定一致——`validateBody` 已实现该协议(`message` 由 `error.issues` 拼出 `path: message` 多行字符串)。
51
+ - 校验规则与 **`src/services/`** 下对应模块中导出的**入参**类型保持同步:**POST** 与「请求体」类型对齐,**GET** 与「查询参数」形状对齐;字段名、可选/必填、基本类型应一致,避免「类型说是 string,Mock 却放过 undefined」。
52
+
53
+ ## 响应体
54
+
55
+ - 成功响应的结构应与 **`src/services/`** 中导出的响应类型一致(状态码字段、消息字段、业务负载层级),便于页面 **`request<响应, 请求>(...)`** 的泛型与实际一致。
56
+ - 需要随机/占位数据时可用 **mockjs** 占位规则;注意与类型声明中的字段类型兼容(例如数值、字符串、嵌套对象)。
57
+
58
+ ## 可选:经页面参数透传到真实后端
59
+
60
+ - **优先使用 `<%= packageScope %>/utils/mock` 的 `tryProxy`**:从 **`referer`** 解析约定查询参数 **`remote`**,命中合法 `http(s):` URL 时用 `http-proxy` 转发并返回 `true`。
61
+ - 透传成功时应**直接 `return`** 当前 handler(`tryProxy` 内部已经写过响应),不再执行本地 Mock 的 **`res.json`**。透传失败或未带参数时走本地 Mock。
62
+ - 若业务需要更复杂的转发逻辑(自定义 header、body 改写等),可在调用 `tryProxy` 前后扩展,或反馈给 `<%= packageScope %>/utils/mock` 增加能力,**避免**在每个子应用里重复实现一遍。
63
+
64
+ ## 与 `src/services/` 类型的配套
65
+
66
+ 请求/响应类型与服务函数**就近定义**在 **`src/services/`** 下对应模块中(如 **`src/services/user.ts`** 同时 `export` 类型 interface 与业务函数),与 Mock、**`<%= packageScope %>/request`** 的泛型共用一套形状。
67
+
68
+ - **按领域或接口维度拆分**多个服务模块,避免单文件无限膨胀。
69
+ - **入参类型**:**写 body 的接口**用 interface 描述 **`data`/body**;**写 query 的接口**用 interface 描述查询参数(与 Mock 里校验的 **`req.query`** 一致;命名由团队统一即可)。
70
+ - **响应体**:导出顶层 interface,通常包含**状态码、提示文案**以及与后端契约一致的**业务负载**字段;负载较深时拆成**嵌套 interface**(子结构单独命名,便于复用与阅读)。
71
+ - **与运行时一致**:Mock 的 JSON 形态、页面 **`data`** 字段、泛型参数三者应指向同一套类型;修改契约时同步改服务模块中的类型、Mock 与调用处。
72
+ - 在组件中通过 **`import { type … } from '@/services/…'`** 引用类型,与服务函数一起导入。
73
+
74
+ ## 依赖
75
+
76
+ - **mockjs**、**zod**、**http-proxy** 等通常挂在 monorepo **根** **`devDependencies`**,由 pnpm 提升解析;若某环境解析失败,再在子应用内显式声明。
77
+
78
+ ## 交叉引用
79
+
80
+ - URL 拼接与 **`rawUrl`** 等见 **`.cursor/rules/workspace-request.mdc`** 与 **`.cursor/rules/internal-packages.mdc`**(**`domain`**)。
@@ -0,0 +1,52 @@
1
+ ---
2
+ description: <%= packageScope %>/request 统一请求封装、URL 解析、拦截器与泛型用法
3
+ globs: packages/request/**/*.{ts,tsx}
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # `<%= packageScope %>/request`(`packages/request`)
8
+
9
+ ## 定位
10
+
11
+ - 对 Umi 运行时 **`request`** 的封装:在发出请求前解析最终 URL、跑请求链拦截器,在返回后跑响应链拦截器,并对错误做统一归一化。
12
+ - 与 **`<%= packageScope %>/domain`** 中的 **`apiBaseUrl`** 配合:相对路径会拼成完整 URL;**绝对 URL** 或 **`rawUrl: true`** 时不再拼接。
13
+ - 供业务页面使用;**`<%= packageScope %>/common-intl`** 的 **`init()`** 内部已绑定该实例作为 `requestInstance`,保证与中台、网关的路径规则一致。
14
+ - 依赖 **`<%= packageScope %>/domain`** 与 **`<%= packageScope %>/js-bridge`**(`buildDefaultHeaders` 中预留 `getUserInfo()` 取 token 的位置,模板里已注释,业务侧打开后会自动注入到默认请求头)。
15
+
16
+ ## 公开 API(概念)
17
+
18
+ - **`request(url, options?)`**:主入口;泛型 **`T`** 为**响应数据类型**,**`P`** 为 **`data` / `params`** 等载荷形状(见包内 **`UnifiedRequestOptions`**)。
19
+ - **拦截器**:**`registerRequestInterceptor` / `registerResponseInterceptor`**(或包内与 **`add*`** 等价的导出)用于注册;执行顺序以包内实现为准。默认拦截器在模块加载时初始化。
20
+ - **`withTemporaryInterceptors(runner, { request?, response? })`**:在**单次**异步任务上临时挂载拦截器,结束后卸载,避免污染全局。
21
+ - **类型**:从包入口 **`export type`** 引用 **`UnifiedRequestOptions`**、**`RequestInterceptor`**、**`ResponseInterceptor`** 等;不要在应用里深链未导出的内部路径。
22
+
23
+ ## `UnifiedRequestOptions` 要点
24
+
25
+ - 支持 **`method`**、**`headers`**、**`data`**、**`params`**、**`responseType`** 等与 Umi/Ajax 常见选项对齐的字段;具体以 **`types.ts`** 为准。
26
+ - **`rawUrl: true`**:完全跳过 URL 解析,直接使用传入的 **`url`**(用于已完整 URL 或特殊场景)。
27
+ - **`baseURL`**:若提供,用于覆盖全局 base(与 **`domain`** 解析结果的关系以 **`url-resolver`** 实现为准)。
28
+ - **`skipRequestInterceptors` / `skipResponseInterceptors`**:跳过请求/响应链上的统一拦截器;`common-intl` 的 `init()` 内部使用 `skipRequestInterceptors: true` 调多语言接口,避免被业务拦截器干扰。
29
+ - **`isShowLoading`**:**默认 `true`**,与包内「请求池」配合做并发显隐;不需要全局 loading 的接口(如多语言、上报)显式传 `false` 关闭。
30
+
31
+ ## URL 解析(`resolveRequestUrl`)
32
+
33
+ 优先级概括:**`rawUrl`** → **已是绝对 URL** → **存在 `apiBaseUrl` 则拼接** → 否则退回原始 **`url`**。
34
+ **`apiBaseUrl`** 来自 **`<%= packageScope %>/domain`**(运行时配置与环境变量回退),修改环境时 Mock 注册的键与这里必须一致。
35
+
36
+ ## 错误处理
37
+
38
+ - 区分 Axios 类错误与业务封装的错误类型,抽取 **`message`** 再提示或抛出;当前 `request` 兜底使用 **`alert(message)`** 提示——业务有统一 toast / Modal 时,应通过 `registerResponseInterceptor` 抛出 `NormalResponseError` 并在外层捕获,或在合适时机替换包内默认行为。
39
+ - 默认响应拦截器(`interceptors.ts`)按 `{ code, message }` 形态校验:`code` 不为 `200/0` 时抛 `NormalResponseError`;非对象响应统一抛错。修改业务后端响应契约时同步本拦截器与 **`apps/<子应用>/src/services/`** 中的响应类型。
40
+
41
+ ## Umi 侧配置
42
+
43
+ - **`<%= packageScope %>/umi-config`** 的 **`createBaseConfig`** 已默认启用 **`@umijs/plugins/dist/request`** 并写入 **`request: {}`**;子应用直接 `import` 工厂即可,**不需要**在 `config/config.ts` 里再写一遍 `plugins` 与 `request`。
44
+ - 想自定义 `request` 配置时,把覆盖项作为 `createBaseConfig` 的 `options` 传入即可(默认会被业务覆盖项浅合并)。
45
+
46
+ ## 与类型、Mock 的配合
47
+
48
+ - 页面调用 **`request<响应类型, 请求载荷类型>(相对或绝对路径, { method, data, … })`** 时,两类泛型应与 **`apps/<子应用>/src/services/`** 下对应模块中导出的类型及 Mock 返回体一致。详见 **`.cursor/rules/umi-mock.mdc`**。
49
+
50
+ ## 修改包时的注意点
51
+
52
+ - 改动 **`types`** 或拦截器签名会影响 **`common-intl`** 中 **`init()`** 对 `request` 的引用;改完后跑包级 **`lint`**,并在依赖该包的应用里做一次类型检查。