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,56 @@
1
+ {
2
+ "name": "<%= projectName %>",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "author": "<%= author %>",
6
+ "packageManager": "pnpm@10.18.2",
7
+ "scripts": {
8
+ "dev": "node scripts/dev.js",
9
+ "dev:preset": "node scripts/dev-preset.js",
10
+ "list:preset": "node scripts/dev-preset.js --list",
11
+ "dev:gateway": "dotenv -e .env -e .env.local -e .env.development -e .env.development.local -- node scripts/gateway.ts",
12
+ "build": "dotenv -e .env -e .env.local -e .env.production -e .env.production.local -- turbo run build && node scripts/collect-dist.js",
13
+ "build:development": "dotenv -e .env -e .env.local -e .env.development -e .env.development.local -- turbo run build:development ${TURBO_FILTER:+--filter=${TURBO_FILTER}} && node scripts/collect-dist.js",
14
+ "build:testing": "dotenv -e .env -e .env.local -e .env.testing -e .env.testing.local -- turbo run build:testing ${TURBO_FILTER:+--filter=${TURBO_FILTER}} && node scripts/collect-dist.js",
15
+ "build:production": "dotenv -e .env -e .env.local -e .env.production -e .env.production.local -- turbo run build:production ${TURBO_FILTER:+--filter=${TURBO_FILTER}} && node scripts/collect-dist.js",
16
+ "lint": "turbo run lint",
17
+ "lint:fix": "turbo run lint:fix",
18
+ "lint-staged": "lint-staged",
19
+ "prepare": "husky"
20
+ },
21
+ "devDependencies": {
22
+ "@commitlint/cli": "^20.5.0",
23
+ "@commitlint/config-conventional": "^20.5.0",
24
+ "@types/http-proxy": "^1.17.17",
25
+ "@types/mockjs": "^1.0.10",
26
+ "@types/node": "^20",
27
+ "chalk": "^5.6.2",
28
+ "dotenv-cli": "^11.0.0",
29
+ "eslint": "catalog:",
30
+ "http-proxy": "^1.18.1",
31
+ "husky": "^9.1.7",
32
+ "lint-staged": "^16.4.0",
33
+ "mockjs": "^1.1.0",
34
+ "portfinder": "^1.0.38",
35
+ "prettier": "^3.8.1",
36
+ "prettier-plugin-organize-imports": "^3.2.2",
37
+ "prettier-plugin-packagejson": "^2.4.3",
38
+ "stylelint": "catalog:",
39
+ "turbo": "^2.8.20",
40
+ "typescript": "^5",
41
+ "zod": "^4.3.6"
42
+ },
43
+ "pnpm": {
44
+ "overrides": {
45
+ "eslint": "catalog:",
46
+ "jiti": "^2"
47
+ },
48
+ "peerDependencyRules": {
49
+ "allowedVersions": {
50
+ "eslint": "9",
51
+ "react": "18",
52
+ "react-dom": "18"
53
+ }
54
+ }
55
+ }
56
+ }
@@ -0,0 +1,180 @@
1
+ # <%= packageScope %>/common-intl
2
+
3
+ 本包是 [`@common-web/common-intl`](https://gitlab-vywrajy.micoworld.net/micocenter/mico-portal/portal-center/common-web/-/blob/release/0.0.9/packages/common-intl/README.md) 的项目级封装:re-export 上游全部 API,并提供预配置的 **`init()`** 函数(自动绑定 `<%= packageScope %>/request`、`langBaseUrl`、`configureLocale`),子应用开箱即用。
4
+
5
+ - **无构建步骤**:`package.json` 的 `exports` 直接指向 `./src/index.ts`(源码 TS),依赖方 dev / build 即可
6
+ - 依赖:`@common-web/common-intl`、`<%= packageScope %>/domain`(`langBaseUrl`)、`<%= packageScope %>/request`(`request`)
7
+
8
+ ## 微前端模式
9
+
10
+ 在 qiankun 微前端架构中,**主应用负责获取文案**,子应用直接使用共享的文案对象,无需重复初始化。
11
+
12
+ ```
13
+ ┌─────────────────────────────────────────────────────────┐
14
+ │ apps/layout(主应用) │
15
+ │ initIntl() 绑定 tag → render() 中 fetchMultilingualData │
16
+ │ → 文案存储到 window.__MICO_COMMON_INTL_TRANSLATIONS__ │
17
+ └─────────────────────────────────────────────────────────┘
18
+
19
+ ┌─────────────────────┼─────────────────────┐
20
+ ↓ ↓ ↓
21
+ ┌───────────┐ ┌───────────┐ ┌───────────┐
22
+ │ 子应用 A │ │ 子应用 B │ │ 子应用 C │
23
+ │ import { │ │ import { │ │ import { │
24
+ │ intl │ │ intl │ │ intl │
25
+ │ } │ │ } │ │ } │
26
+ │ 直接使用 │ │ 直接使用 │ │ 直接使用 │
27
+ └───────────┘ └───────────┘ └───────────┘
28
+ ```
29
+
30
+ ## 快速开始(子应用推荐方式)
31
+
32
+ `init()` 是本包提供的便捷入口,已预绑定 `<%= packageScope %>/request` 和 `langBaseUrl`,子应用只需提供 `tag` 和 `indexedDBParams`。
33
+
34
+ ### 1. 初始化 & 定义文案(`src/intl.ts`)
35
+
36
+ ```typescript
37
+ import { addIntl, init } from '<%= packageScope %>/common-intl';
38
+
39
+ const { fetchMultilingualData, i18n } = init({
40
+ tag: 'your_tag', // 替换为多语言中台的标签
41
+ indexedDBParams: { dbName: 'i18n_your_tag' },
42
+ });
43
+
44
+ const intl = addIntl(
45
+ {
46
+ common_hello: () =>
47
+ i18n({ key: 'common_hello', defaultMessage: '你好' }),
48
+ common_welcome_aa: (name: string) =>
49
+ i18n({ key: 'common_welcome_aa', interpolations: [name], defaultMessage: `欢迎, ${name}` }),
50
+ },
51
+ i18n,
52
+ );
53
+
54
+ export { fetchMultilingualData };
55
+ export default intl;
56
+ ```
57
+
58
+ ### 2. 首屏前加载文案(`src/app.tsx`)
59
+
60
+ ```typescript
61
+ import { fetchMultilingualData } from '@/intl';
62
+
63
+ export function render(oldRender: () => void) {
64
+ fetchMultilingualData()
65
+ .then(oldRender)
66
+ .catch((error: Error) => {
67
+ console.error('获取多语言文案失败', error);
68
+ oldRender();
69
+ });
70
+ }
71
+ ```
72
+
73
+ ### 3. 业务组件中使用
74
+
75
+ ```typescript
76
+ import intl from '@/intl';
77
+
78
+ intl.common_hello(); // '你好'
79
+ intl.common_welcome_aa('张三'); // '欢迎, 张三'
80
+ ```
81
+
82
+ 占位符为 `%AA%`、`%BB%`…,与 `interpolations` 数组顺序对应。
83
+
84
+ ## 主应用接入
85
+
86
+ 主应用(如 `apps/layout`)需要更多控制,可直接使用上游 `initIntl` + 完整参数的 `fetchMultilingualData`:
87
+
88
+ ```typescript
89
+ import { fetchMultilingualData, getCurrentLocale, type ILang } from '<%= packageScope %>/common-intl';
90
+
91
+ export function render(oldRender: () => void): void {
92
+ fetchMultilingualData({
93
+ requestInstance: commonRequest,
94
+ messageInstance: {
95
+ error: micoUI.Message.error,
96
+ warning: micoUI.Message.warning,
97
+ },
98
+ lang: getCurrentLocale() as ILang,
99
+ localeRequestUrl: process.env.LOCALE_REQUEST_URL,
100
+ })
101
+ .then(oldRender)
102
+ .catch((error: Error) => {
103
+ console.error('获取多语言文案失败', error);
104
+ oldRender();
105
+ });
106
+ }
107
+ ```
108
+
109
+ > **区别**:`init()` 返回的 `fetchMultilingualData()` 已预绑定 `requestInstance`、`messageInstance`、`lang`、`localeRequestUrl`,无需再传参;上游的 `fetchMultilingualData(params)` 需要手动传入全部运行时参数。
110
+
111
+ ## 子应用使用模式
112
+
113
+ ### 默认模式:共享主应用文案
114
+
115
+ 子应用默认与主应用共享同一个 `tag`,直接导入即可使用,**无需调用 `initIntl`**:
116
+
117
+ ```typescript
118
+ import { intl } from '<%= packageScope %>/common-intl';
119
+
120
+ intl.common_hello();
121
+ ```
122
+
123
+ 主应用通过 `window` 暴露 `<%= packageScope %>/common-intl`,子应用通过 `externals` 复用,不会重复打包。
124
+
125
+ ### 独立 tag 模式
126
+
127
+ 如果子应用需要使用**独立的多语言标签**(例如子应用有自己的多语言文案),直接依赖 `@common-web/common-intl`,在子应用内自行调用 `initIntl`,不需要经过本中转包:
128
+
129
+ ```typescript
130
+ // apps/my-subapp/src/locales/index.ts
131
+ import { initIntl, addIntl } from '@common-web/common-intl';
132
+
133
+ const { fetchMultilingualData, i18n } = initIntl({
134
+ tag: 'my_subapp_tag',
135
+ app_name: 'middle',
136
+ indexedDBParams: { dbName: 'my_subapp_i18n_db' },
137
+ });
138
+
139
+ export { fetchMultilingualData };
140
+
141
+ const intl = addIntl({
142
+ my_key: () => i18n({ key: 'my_key', defaultMessage: '我的文案' }),
143
+ }, i18n);
144
+
145
+ export default intl;
146
+ ```
147
+
148
+ > `initIntl` 只管身份配置(tag、app_name、存储),`fetchMultilingualData` 管运行时依赖(请求实例、消息提示、语言、API 地址)。`i18n` 函数与 `tag` 绑定,不同 tag 的翻译数据互相隔离。
149
+
150
+ ## `init()` 内部行为
151
+
152
+ `init(params)` 接收 `IInitIntlParams`(`app_name` 可选,默认 `<%= projectName %>`),执行:
153
+
154
+ 1. **`configureLocale`**:配置自定义 locale 获取/设置(H5 一般通过 JSBridge;默认模板返回 `'en'`,请按实际需求修改 `src/intl.ts` 中的 `getLocale` / `setLocale`)
155
+ 2. **`initIntl`**:绑定 `tag`、`app_name`、`indexedDBParams`
156
+ 3. 返回 **`fetchMultilingualData()`**(已绑定 `request` / `langBaseUrl` / 默认 `messageInstance`)和 **`i18n`**
157
+
158
+ ## 常见问题
159
+
160
+ ### Q: 子应用需要调用 initIntl 吗?
161
+
162
+ 默认不需要。主应用负责初始化和获取文案,子应用直接使用共享的 `intl` 对象。仅当子应用需要独立 tag 时才自行调用。
163
+
164
+ ### Q: 翻译数据什么时候加载?
165
+
166
+ 在 UmiJS 的 `render` 钩子中调用 `fetchMultilingualData()`,确保在应用渲染前完成加载。
167
+
168
+ ### Q: 如何添加新的翻译文案?
169
+
170
+ 在 `src/intl.ts` 的 `addIntl` 中添加对应的函数,然后在组件中通过 `intl.xxx()` 调用。
171
+
172
+ ### Q: 修改包内代码后需要构建吗?
173
+
174
+ 不需要。`exports` 直接指向源码 TS,依赖方重新 dev / build 即可生效。
175
+
176
+ ## 完整文档
177
+
178
+ 关于 `initIntl`、`fetchMultilingualData`、`i18n`、`addIntl` 的详细 API、类型定义、缓存策略、占位符规则等,请参阅:
179
+
180
+ **[@common-web/common-intl README](https://gitlab-vywrajy.micoworld.net/micocenter/mico-portal/portal-center/common-web/-/blob/release/0.0.9/packages/common-intl/README.md)**
@@ -0,0 +1,12 @@
1
+ import baseConfig from '<%= packageScope %>/eslint';
2
+ import { defineConfig } from 'eslint/config';
3
+ export default defineConfig([
4
+ ...baseConfig,
5
+ {
6
+ languageOptions: {
7
+ parserOptions: {
8
+ tsconfigRootDir: import.meta.dirname,
9
+ },
10
+ },
11
+ },
12
+ ]);
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "<%= packageScope %>/common-intl",
3
+ "version": "0.0.1",
4
+ "description": "通用国际化库 - re-exports @common-web/common-intl",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./src/index.ts",
9
+ "types": "./src/index.ts"
10
+ }
11
+ },
12
+ "files": [
13
+ "src"
14
+ ],
15
+ "dependencies": {
16
+ "@common-web/common-intl": "^0.4.1",
17
+ "<%= packageScope %>/domain": "workspace:^",
18
+ "<%= packageScope %>/js-bridge": "workspace:^",
19
+ "<%= packageScope %>/request": "workspace:^"
20
+ },
21
+ "keywords": [
22
+ "i18n",
23
+ "intl",
24
+ "internationalization",
25
+ "mico"
26
+ ],
27
+ "devDependencies": {
28
+ "<%= packageScope %>/eslint": "workspace:^",
29
+ "<%= packageScope %>/typescript": "workspace:^"
30
+ }
31
+ }
@@ -0,0 +1,3 @@
1
+ export * from '@common-web/common-intl';
2
+
3
+ export { init } from './intl';
@@ -0,0 +1,100 @@
1
+ import {
2
+ configureLocale,
3
+ type IFetchParams,
4
+ type IInitIntlParams,
5
+ ILang,
6
+ initIntl,
7
+ } from '@common-web/common-intl';
8
+ import { langBaseUrl } from '<%= packageScope %>/domain';
9
+ import getUserInfo from '<%= packageScope %>/js-bridge/getUserInfo';
10
+ import { request, type UnifiedRequestOptions } from '<%= packageScope %>/request';
11
+
12
+ type PartialProps<T extends object, K extends keyof T> = Partial<Pick<T, K>> &
13
+ Omit<T, K>;
14
+
15
+ /**
16
+ * 使用<%= packageScope %>/request和@common-web/common-intl初始化国际化
17
+ * @param params 国际化参数
18
+ * @returns 国际化对象
19
+ */
20
+ export const init = (params: PartialProps<IInitIntlParams, 'app_name'>) => {
21
+ /**
22
+ * 配置自定义的 locale 获取/设置行为,
23
+ * h5一般会使用客户端提供的JSBridge来获取语言
24
+ */
25
+ const { fetchMultilingualData: fetchMultilingualDataFn, i18n } = initIntl({
26
+ tag: params.tag,
27
+ app_name: params.app_name ?? '<%= projectName %>',
28
+ indexedDBParams: params.indexedDBParams,
29
+ });
30
+ const fetchMultilingualData = async () => {
31
+ let lang: ILang = 'en';
32
+ try {
33
+ const userInfo = await getUserInfo();
34
+ lang = userInfo.lang as ILang;
35
+ } catch (error) {
36
+ console.error(error);
37
+ lang = 'en';
38
+ }
39
+ configureLocale({
40
+ getLocale: () => {
41
+ return lang;
42
+ },
43
+ setLocale: (locale: string) => {
44
+ console.log('setLocale', locale);
45
+ },
46
+ });
47
+ return fetchMultilingualDataFn({
48
+ requestInstance: ((url: string, options) => {
49
+ return request(url, {
50
+ ...options,
51
+ skipRequestInterceptors: true,
52
+ } as UnifiedRequestOptions);
53
+ }) as IFetchParams['requestInstance'],
54
+ messageInstance: {
55
+ error: (msg: string) => {
56
+ console.error(msg);
57
+ },
58
+ warning: (msg: string) => {
59
+ console.warn(msg);
60
+ },
61
+ },
62
+ lang,
63
+ localeRequestUrl: langBaseUrl,
64
+ });
65
+ };
66
+ return {
67
+ fetchMultilingualData,
68
+ i18n,
69
+ };
70
+ };
71
+
72
+ /**
73
+ * 子应用使用方式:
74
+ * import { init } from '<%= packageScope %>/common-intl';
75
+ *
76
+ * 1. 初始化国际化
77
+ * const { fetchMultilingualData, i18n } = init({
78
+ * tag: 'tag',
79
+ * app_name: '<%= projectName %>', // 可不传,默认是'<%= projectName %>'
80
+ * indexedDBParams: { dbName: `<%= projectName %>_i18n_${tag}` },
81
+ * });
82
+ *
83
+ * 2. 添加文案
84
+ * const intl = addIntl(
85
+ * {
86
+ * common_hello: () => i18n({ key: 'common_hello', defaultMessage: '你好' }),
87
+ * common_welcome_aa: (name: string) => i18n({ key: 'common_welcome_aa', interpolations: [name], defaultMessage: `欢迎, ${name}` }),
88
+ * },
89
+ * i18n,
90
+ * );
91
+ * export default intl;
92
+ *
93
+ * 3. 调用方法
94
+ * fetchMultilingualData();
95
+ *
96
+ * 4. 使用文案
97
+ * import intl from '@/intl';
98
+ * intl.common_hello();
99
+ * intl.common_welcome_aa('张三');
100
+ */
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "<%= packageScope %>/typescript"
3
+ }
@@ -0,0 +1,12 @@
1
+ import baseConfig from '<%= packageScope %>/eslint/react';
2
+ import { defineConfig } from 'eslint/config';
3
+ export default defineConfig([
4
+ ...baseConfig,
5
+ {
6
+ languageOptions: {
7
+ parserOptions: {
8
+ tsconfigRootDir: import.meta.dirname,
9
+ },
10
+ },
11
+ },
12
+ ]);
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "<%= packageScope %>/components",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "./src/index.ts",
7
+ "scripts": {
8
+ "postinstall": "umi setup",
9
+ "setup": "umi setup",
10
+ "lint": "eslint",
11
+ "lint:fix": "eslint --fix"
12
+ },
13
+ "exports": {
14
+ ".": "./src/index.ts",
15
+ "./Layout": "./src/Layout/index.tsx",
16
+ "./assets/*": "./src/assets/*"
17
+ },
18
+ "devDependencies": {
19
+ "umi": "catalog:",
20
+ "<%= packageScope %>/eslint": "workspace:^",
21
+ "@types/react": "catalog:",
22
+ "@types/react-dom": "catalog:"
23
+ },
24
+ "dependencies": {
25
+ "<%= packageScope %>/js-bridge": "workspace:^",
26
+ "<%= packageScope %>/utils": "workspace:^"
27
+ },
28
+ "peerDependencies": {
29
+ "react": "catalog:",
30
+ "react-dom": "catalog:"
31
+ }
32
+ }
@@ -0,0 +1,126 @@
1
+ import closeH5Page from '<%= packageScope %>/js-bridge/closeH5Page';
2
+ import { cn, cva, type VariantProps } from '<%= packageScope %>/utils/tailwind';
3
+ import {
4
+ useCallback,
5
+ useLayoutEffect,
6
+ useState,
7
+ type FC,
8
+ type PropsWithChildren,
9
+ type ReactNode,
10
+ } from 'react';
11
+ import { history } from 'umi';
12
+
13
+ // 图片
14
+ import backIcon from '<%= packageScope %>/components/assets/image/back.png';
15
+
16
+ // 记录 SPA 内相对入口页的栈深度,用于判断当前页是否为首屏(无应用内历史)。
17
+ // 注意:window.history.length 会受同 tab/Webview 内此前页面影响,不能直接依赖;
18
+ let inAppNavCount = 0;
19
+ history.listen(({ action }) => {
20
+ if (action === 'PUSH') {
21
+ inAppNavCount += 1;
22
+ } else if (action === 'POP') {
23
+ inAppNavCount = Math.max(0, inAppNavCount - 1);
24
+ }
25
+ // REPLACE 不改变栈深度,忽略
26
+ });
27
+
28
+ const headerVariants = cva('flex items-center justify-between py-2 px-4', {
29
+ variants: {
30
+ variant: {
31
+ light: 'bg-white',
32
+ dark: 'bg-[#0C0C15]',
33
+ transparent: 'bg-transparent',
34
+ },
35
+ },
36
+ defaultVariants: {
37
+ variant: 'dark',
38
+ },
39
+ });
40
+
41
+ const titleVariants = cva(
42
+ 'font-medium text-center text-[18px] overflow-hidden text-ellipsis whitespace-nowrap',
43
+ {
44
+ variants: {
45
+ variant: {
46
+ light: 'text-[#0C0C15]',
47
+ dark: 'text-white',
48
+ transparent: 'text-white',
49
+ },
50
+ },
51
+ defaultVariants: {
52
+ variant: 'dark',
53
+ },
54
+ },
55
+ );
56
+
57
+ interface HeaderProps
58
+ extends PropsWithChildren, VariantProps<typeof headerVariants> {
59
+ end?: ReactNode;
60
+ className?: string;
61
+ }
62
+
63
+ /**
64
+ * 默认头部组件。
65
+ */
66
+ const DefaultHeader: FC<HeaderProps> = ({ end, variant }) => {
67
+ const [title, setTitle] = useState(document.title);
68
+ useLayoutEffect(() => {
69
+ let titleElement = document.querySelector('title');
70
+ if (!titleElement) {
71
+ titleElement = document.createElement('title');
72
+ document.head.appendChild(titleElement);
73
+ }
74
+ const observer = new MutationObserver(() => {
75
+ setTitle(document.title);
76
+ });
77
+ observer.observe(titleElement, {
78
+ childList: true,
79
+ subtree: true,
80
+ });
81
+ return () => {
82
+ observer.disconnect();
83
+ };
84
+ }, []);
85
+
86
+ // 有应用内路由历史时返回上一页,否则关闭当前页面
87
+ const handleBack = useCallback(() => {
88
+ if (inAppNavCount > 0) {
89
+ history.back();
90
+ } else {
91
+ closeH5Page();
92
+ }
93
+ }, []);
94
+
95
+ return (
96
+ <div className={headerVariants({ variant })}>
97
+ <div className="flex-shrink-0 size-6" onClick={handleBack}>
98
+ <img src={backIcon} className="size-full" alt="back" />
99
+ </div>
100
+ <div className="flex flex-1 items-center justify-center overflow-hidden">
101
+ <h1 className={titleVariants({ variant })}>{title}</h1>
102
+ </div>
103
+ <div className="flex-shrink-0 size-6 flex items-center justify-center">
104
+ {end}
105
+ </div>
106
+ </div>
107
+ );
108
+ };
109
+
110
+ /**
111
+ * 沉浸式布局头部组件。
112
+ */
113
+ const ImmersiveHeader: FC<HeaderProps> = ({
114
+ children,
115
+ end,
116
+ className,
117
+ variant,
118
+ }) => {
119
+ return (
120
+ <header className={cn('flex-shrink-0 pt-safe', className)}>
121
+ {children ?? <DefaultHeader end={end} variant={variant} />}
122
+ </header>
123
+ );
124
+ };
125
+
126
+ export default ImmersiveHeader;
@@ -0,0 +1,72 @@
1
+ import { cn } from '<%= packageScope %>/utils/tailwind';
2
+ import { useEffect, useRef, type FC, type PropsWithChildren } from 'react';
3
+
4
+ export interface LayoutFooterProps extends PropsWithChildren {
5
+ /** 底部区域附加样式 */
6
+ className?: string;
7
+ /** 底部内容是否固定 */
8
+ fixed?: boolean;
9
+ /** 底部内容高度变化回调 */
10
+ onFooterHeightChange?: (height: number) => void;
11
+ }
12
+
13
+ /**
14
+ * 底部区域组件。
15
+ * - 无 children 时仅渲染底部安全区域占位。
16
+ * - fixed 模式下使用 fixed 定位,并通过 ResizeObserver 计算高度,main区域设置 padding-bottom 避免遮挡内容。
17
+ * 底部安全区 padding 通过 `[&>*]:pb-safe-or-4` 自动应用到直接子元素上,
18
+ * 这样调用方写在子元素上的背景(实色或渐变)会天然覆盖到安全区域,无需手动添加。
19
+ */
20
+ const LayoutFooter: FC<LayoutFooterProps> = ({
21
+ children,
22
+ className,
23
+ fixed,
24
+ onFooterHeightChange,
25
+ }) => {
26
+ const footerRef = useRef<HTMLElement>(null);
27
+
28
+ useEffect(() => {
29
+ if (!fixed) return;
30
+ const el = footerRef.current;
31
+ if (!el) return;
32
+ const observer = new ResizeObserver(() => {
33
+ const height = el.offsetHeight;
34
+ onFooterHeightChange?.(height);
35
+ });
36
+ observer.observe(el);
37
+ return () => observer.disconnect();
38
+ }, [fixed, onFooterHeightChange]);
39
+
40
+ // 无子元素时,仅渲染底部安全区域占位。
41
+ if (!children) {
42
+ return (
43
+ <div className={cn('flex-shrink-0 w-full pb-safe-or-4', className)} />
44
+ );
45
+ }
46
+
47
+ // fixed 模式下,使用 fixed 定位,并通过 ResizeObserver 计算高度,main区域设置 padding-bottom 避免遮挡内容。
48
+ if (fixed) {
49
+ return (
50
+ <footer
51
+ ref={footerRef}
52
+ className={cn(
53
+ 'fixed bottom-0 left-0 right-0 z-40 px-safe [&>*]:pb-safe-or-4',
54
+ className,
55
+ )}
56
+ >
57
+ {children}
58
+ </footer>
59
+ );
60
+ }
61
+
62
+ // 非 fixed 模式
63
+ return (
64
+ <footer
65
+ className={cn('flex-shrink-0 w-full [&>*]:pb-safe-or-4', className)}
66
+ >
67
+ {children}
68
+ </footer>
69
+ );
70
+ };
71
+
72
+ export default LayoutFooter;