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.
- package/README.md +145 -18
- package/bin/mico.js +76 -0
- package/generators/h5-react/ignore-list.json +1 -0
- package/generators/h5-react/index.js +349 -0
- package/generators/h5-react/meta.json +11 -0
- package/generators/h5-react/templates/.commitlintrc.js +7 -0
- package/generators/h5-react/templates/.cursor/rules/cicd-deploy.mdc +104 -0
- package/generators/h5-react/templates/.cursor/rules/common-intl.mdc +42 -0
- package/generators/h5-react/templates/.cursor/rules/git-hooks.mdc +40 -0
- package/generators/h5-react/templates/.cursor/rules/internal-packages.mdc +46 -0
- package/generators/h5-react/templates/.cursor/rules/monorepo.mdc +64 -0
- package/generators/h5-react/templates/.cursor/rules/package-json.mdc +52 -0
- package/generators/h5-react/templates/.cursor/rules/tailwind-umi.mdc +60 -0
- package/generators/h5-react/templates/.cursor/rules/umi-app.mdc +74 -0
- package/generators/h5-react/templates/.cursor/rules/umi-config.mdc +86 -0
- package/generators/h5-react/templates/.cursor/rules/umi-mock.mdc +80 -0
- package/generators/h5-react/templates/.cursor/rules/workspace-request.mdc +52 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/SKILL.md +213 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/evals/evals.json +23 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/cursor-rule-template.md +60 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/phase-1-scanning.md +102 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/phase-2-context-analysis.md +102 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/phase-3-pattern-extraction.md +105 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/phase-4-module-mapping.md +65 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/phase-5-glossary.md +63 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/templates/DEV_PATTERNS.tpl.md +77 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/templates/GLOSSARY.tpl.md +17 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/templates/MODULE_MAP.tpl.md +45 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/templates/PROJECT_CONTEXT.tpl.md +155 -0
- package/generators/h5-react/templates/.cursor/skills/biz-app-analyzer/references/update-mode.md +116 -0
- package/generators/h5-react/templates/.env.development +5 -0
- package/generators/h5-react/templates/.env.production +5 -0
- package/generators/h5-react/templates/.env.testing +5 -0
- package/generators/h5-react/templates/.husky/commit-msg +2 -0
- package/generators/h5-react/templates/.husky/pre-commit +2 -0
- package/generators/h5-react/templates/.lintstagedrc.js +8 -0
- package/generators/h5-react/templates/.prettierrc.json +7 -0
- package/generators/h5-react/templates/CICD/before_build.sh +76 -0
- package/generators/h5-react/templates/CICD/start_dev.sh +54 -0
- package/generators/h5-react/templates/CICD/start_local.sh +30 -0
- package/generators/h5-react/templates/CICD/start_prod.sh +53 -0
- package/generators/h5-react/templates/CICD/start_test.sh +55 -0
- package/generators/h5-react/templates/CICD/wangsu_fresh_dev.sh +19 -0
- package/generators/h5-react/templates/CICD/wangsu_fresh_prod.sh +19 -0
- package/generators/h5-react/templates/CICD/wangsu_fresh_test.sh +19 -0
- package/generators/h5-react/templates/README.md +301 -0
- package/generators/h5-react/templates/_gitignore +30 -0
- package/generators/h5-react/templates/_npmrc +6 -0
- package/generators/h5-react/templates/apps/.gitkeep +0 -0
- package/generators/h5-react/templates/dev.preset.json +10 -0
- package/generators/h5-react/templates/package.json +56 -0
- package/generators/h5-react/templates/packages/common-intl/README.md +180 -0
- package/generators/h5-react/templates/packages/common-intl/eslint.config.ts +12 -0
- package/generators/h5-react/templates/packages/common-intl/package.json +31 -0
- package/generators/h5-react/templates/packages/common-intl/src/index.ts +3 -0
- package/generators/h5-react/templates/packages/common-intl/src/intl.ts +100 -0
- package/generators/h5-react/templates/packages/common-intl/tsconfig.json +3 -0
- package/generators/h5-react/templates/packages/components/eslint.config.ts +12 -0
- package/generators/h5-react/templates/packages/components/package.json +32 -0
- package/generators/h5-react/templates/packages/components/src/Layout/ImmersiveHeader.tsx +126 -0
- package/generators/h5-react/templates/packages/components/src/Layout/LayoutFooter.tsx +72 -0
- package/generators/h5-react/templates/packages/components/src/Layout/index.tsx +121 -0
- package/generators/h5-react/templates/packages/components/src/assets/image/back.png +0 -0
- package/generators/h5-react/templates/packages/components/src/index.ts +0 -0
- package/generators/h5-react/templates/packages/components/tsconfig.json +13 -0
- package/generators/h5-react/templates/packages/components/typings.d.ts +1 -0
- package/generators/h5-react/templates/packages/constant/eslint.config.ts +12 -0
- package/generators/h5-react/templates/packages/constant/package.json +19 -0
- package/generators/h5-react/templates/packages/constant/src/index.ts +0 -0
- package/generators/h5-react/templates/packages/constant/src/member.ts +8 -0
- package/generators/h5-react/templates/packages/constant/tsconfig.json +3 -0
- package/generators/h5-react/templates/packages/deeplink/eslint.config.ts +12 -0
- package/generators/h5-react/templates/packages/deeplink/package.json +18 -0
- package/generators/h5-react/templates/packages/deeplink/src/index.ts +7 -0
- package/generators/h5-react/templates/packages/deeplink/tsconfig.json +3 -0
- package/generators/h5-react/templates/packages/domain/eslint.config.ts +12 -0
- package/generators/h5-react/templates/packages/domain/package.json +18 -0
- package/generators/h5-react/templates/packages/domain/src/index.ts +29 -0
- package/generators/h5-react/templates/packages/domain/tsconfig.json +3 -0
- package/generators/h5-react/templates/packages/domain/types.d.ts +11 -0
- package/generators/h5-react/templates/packages/eslint/eslint.config.base.ts +36 -0
- package/generators/h5-react/templates/packages/eslint/eslint.config.react.ts +33 -0
- package/generators/h5-react/templates/packages/eslint/package.json +22 -0
- package/generators/h5-react/templates/packages/js-bridge/eslint.config.ts +17 -0
- package/generators/h5-react/templates/packages/js-bridge/package.json +23 -0
- package/generators/h5-react/templates/packages/js-bridge/src/call.ts +126 -0
- package/generators/h5-react/templates/packages/js-bridge/src/closeH5Page.ts +9 -0
- package/generators/h5-react/templates/packages/js-bridge/src/getUserInfo.ts +96 -0
- package/generators/h5-react/templates/packages/js-bridge/src/index.ts +15 -0
- package/generators/h5-react/templates/packages/js-bridge/tsconfig.json +3 -0
- package/generators/h5-react/templates/packages/js-bridge/type.d.ts +24 -0
- package/generators/h5-react/templates/packages/request/axios.d.ts +42 -0
- package/generators/h5-react/templates/packages/request/eslint.config.ts +17 -0
- package/generators/h5-react/templates/packages/request/package.json +22 -0
- package/generators/h5-react/templates/packages/request/src/index.ts +165 -0
- package/generators/h5-react/templates/packages/request/src/interceptors.ts +126 -0
- package/generators/h5-react/templates/packages/request/src/types.ts +101 -0
- package/generators/h5-react/templates/packages/request/src/url-resolver.ts +66 -0
- package/generators/h5-react/templates/packages/request/src/utils.ts +12 -0
- package/generators/h5-react/templates/packages/request/tsconfig.json +3 -0
- package/generators/h5-react/templates/packages/request/umi.d.ts +94 -0
- package/generators/h5-react/templates/packages/typescript/package.json +11 -0
- package/generators/h5-react/templates/packages/typescript/tsconfig.base.json +23 -0
- package/generators/h5-react/templates/packages/typescript/tsconfig.react.json +7 -0
- package/generators/h5-react/templates/packages/umi-config/eslint.config.ts +12 -0
- package/generators/h5-react/templates/packages/umi-config/package.json +31 -0
- package/generators/h5-react/templates/packages/umi-config/src/config.dev.ts +34 -0
- package/generators/h5-react/templates/packages/umi-config/src/config.prod.development.ts +17 -0
- package/generators/h5-react/templates/packages/umi-config/src/config.prod.production.ts +42 -0
- package/generators/h5-react/templates/packages/umi-config/src/config.prod.testing.ts +17 -0
- package/generators/h5-react/templates/packages/umi-config/src/config.prod.ts +56 -0
- package/generators/h5-react/templates/packages/umi-config/src/config.ts +86 -0
- package/generators/h5-react/templates/packages/umi-config/src/index.ts +25 -0
- package/generators/h5-react/templates/packages/umi-config/src/plugins/apply-sentry-plugin.ts +57 -0
- package/generators/h5-react/templates/packages/umi-config/src/type.d.ts +3 -0
- package/generators/h5-react/templates/packages/umi-config/tsconfig.json +3 -0
- package/generators/h5-react/templates/packages/utils/eslint.config.ts +12 -0
- package/generators/h5-react/templates/packages/utils/package.json +27 -0
- package/generators/h5-react/templates/packages/utils/src/date.ts +21 -0
- package/generators/h5-react/templates/packages/utils/src/env.ts +40 -0
- package/generators/h5-react/templates/packages/utils/src/index.ts +3 -0
- package/generators/h5-react/templates/packages/utils/src/md5.ts +17 -0
- package/generators/h5-react/templates/packages/utils/src/mock.ts +83 -0
- package/generators/h5-react/templates/packages/utils/src/number.ts +23 -0
- package/generators/h5-react/templates/packages/utils/src/tailwind.ts +12 -0
- package/generators/h5-react/templates/packages/utils/src/url.ts +19 -0
- package/generators/h5-react/templates/packages/utils/tsconfig.json +9 -0
- package/generators/h5-react/templates/page.config.ts +1 -0
- package/generators/h5-react/templates/pnpm-workspace.yaml +17 -0
- package/generators/h5-react/templates/scripts/collect-dist.js +78 -0
- package/generators/h5-react/templates/scripts/dev-preset.js +265 -0
- package/generators/h5-react/templates/scripts/dev-preset.schema.json +39 -0
- package/generators/h5-react/templates/scripts/dev.js +133 -0
- package/generators/h5-react/templates/scripts/gateway.ts +241 -0
- package/generators/h5-react/templates/turbo.json +86 -0
- package/generators/subapp-h5/ignore-list.json +1 -0
- package/generators/subapp-h5/index.js +424 -0
- package/generators/subapp-h5/meta.json +10 -0
- package/generators/subapp-h5/templates/.env +1 -0
- package/generators/subapp-h5/templates/.stylelintrc.js +22 -0
- package/generators/subapp-h5/templates/config/config.dev.ts +7 -0
- package/generators/subapp-h5/templates/config/config.prod.development.ts +7 -0
- package/generators/subapp-h5/templates/config/config.prod.production.ts +10 -0
- package/generators/subapp-h5/templates/config/config.prod.testing.ts +7 -0
- package/generators/subapp-h5/templates/config/config.prod.ts +7 -0
- package/generators/subapp-h5/templates/config/config.ts +6 -0
- package/generators/subapp-h5/templates/config/routes.ts +13 -0
- package/generators/subapp-h5/templates/eslint.config.ts +12 -0
- package/generators/subapp-h5/templates/mock/user.ts +34 -0
- package/generators/subapp-h5/templates/package.json +42 -0
- package/generators/subapp-h5/templates/src/app.tsx +14 -0
- package/generators/subapp-h5/templates/src/assets/yay.jpg +0 -0
- package/generators/subapp-h5/templates/src/intl.ts +37 -0
- package/generators/subapp-h5/templates/src/layouts/index.tsx +10 -0
- package/generators/subapp-h5/templates/src/pages/index.tsx +22 -0
- package/generators/subapp-h5/templates/src/services/user.ts +38 -0
- package/generators/subapp-h5/templates/tailwind.config.js +16 -0
- package/generators/subapp-h5/templates/tailwind.css +7 -0
- package/generators/subapp-h5/templates/tsconfig.json +3 -0
- package/generators/subapp-h5/templates/typings.d.ts +1 -0
- package/lib/setup-multica-desktop.js +154 -0
- 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,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,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;
|