generator-mico-cli 0.2.22 → 0.2.24
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 +33 -0
- package/bin/mico.js +15 -2
- package/generators/micro-react/index.js +44 -6
- package/generators/micro-react/meta.json +2 -1
- package/generators/micro-react/templates/CICD/start_dev.sh +12 -2
- package/generators/micro-react/templates/CICD/start_prod.sh +11 -1
- package/generators/micro-react/templates/CICD/start_test.sh +12 -1
- package/generators/micro-react/templates/_gitignore +3 -1
- package/generators/micro-react/templates/_npmrc +1 -0
- package/generators/micro-react/templates/apps/layout/config/config.prod.development.ts +16 -0
- package/generators/micro-react/templates/apps/layout/config/config.prod.testing.ts +16 -0
- package/generators/micro-react/templates/apps/layout/config/config.prod.ts +12 -0
- package/generators/micro-react/templates/apps/layout/docs/feature-/345/276/256/345/211/215/347/253/257/346/250/241/345/274/217.md +0 -1
- package/generators/micro-react/templates/apps/layout/docs/feature-/350/217/234/345/215/225/346/235/203/351/231/220/346/216/247/345/210/266.md +9 -8
- package/generators/micro-react/templates/apps/layout/mock/api.mock.ts +81 -61
- package/generators/micro-react/templates/apps/layout/mock/pages.ts +3 -3
- package/generators/micro-react/templates/apps/layout/src/app.tsx +5 -2
- package/generators/micro-react/templates/apps/layout/src/common/menu/parser.ts +7 -2
- package/generators/micro-react/templates/apps/layout/src/common/request/interceptors.ts +29 -1
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.less +1 -5
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/AvatarDropdown.tsx +12 -16
- package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +2 -1
- package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +7 -8
- package/generators/micro-react/templates/apps/layout/src/services/user.ts +5 -1
- package/generators/micro-react/templates/package.json +2 -0
- package/generators/micro-react/templates/scripts/apply-sentry-plugin.ts +45 -0
- package/generators/micro-react/templates/scripts/collect-dist.js +10 -0
- package/generators/micro-react/templates/turbo.json +1 -1
- package/generators/subapp-react/index.js +46 -4
- package/generators/subapp-react/templates/homepage/config/config.dev.ts +0 -1
- package/generators/subapp-react/templates/homepage/config/config.prod.development.ts +9 -2
- package/generators/subapp-react/templates/homepage/config/config.prod.testing.ts +9 -2
- package/generators/subapp-react/templates/homepage/config/config.prod.ts +9 -2
- package/generators/subapp-react/templates/homepage/package.json +1 -0
- package/generators/subapp-react/templates/homepage/src/app.tsx +6 -0
- package/generators/subapp-umd/ignore-list.json +5 -0
- package/generators/subapp-umd/index.js +325 -0
- package/generators/subapp-umd/meta.json +11 -0
- package/generators/subapp-umd/templates/README.md +94 -0
- package/generators/subapp-umd/templates/package.json +35 -0
- package/generators/subapp-umd/templates/public/index.html +34 -0
- package/generators/subapp-umd/templates/src/App.less +15 -0
- package/generators/subapp-umd/templates/src/App.tsx +13 -0
- package/generators/subapp-umd/templates/src/index.ts +2 -0
- package/generators/subapp-umd/templates/tsconfig.json +27 -0
- package/generators/subapp-umd/templates/webpack.config.js +68 -0
- package/lib/utils.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
| [docs/mico-cli.md](docs/mico-cli.md) | Mico CLI 功能概述与技术方案 |
|
|
10
10
|
| [docs/micro-react-generator.md](docs/micro-react-generator.md) | Monorepo 项目生成器说明 |
|
|
11
11
|
| [docs/subapp-react-generator.md](docs/subapp-react-generator.md) | React 子应用生成器说明 |
|
|
12
|
+
| [docs/subapp-umd-generator.md](docs/subapp-umd-generator.md) | UMD 组件包生成器说明 |
|
|
12
13
|
|
|
13
14
|
## 要求
|
|
14
15
|
|
|
@@ -97,6 +98,7 @@ mico create micro-react
|
|
|
97
98
|
- @mico-platform/ui、@mico-platform/theme
|
|
98
99
|
- Turborepo + pnpm Workspace
|
|
99
100
|
- Husky + Commitlint
|
|
101
|
+
- @common-web/sentry 错误监控与 SourceMap 上传
|
|
100
102
|
|
|
101
103
|
## React 子应用生成器
|
|
102
104
|
|
|
@@ -108,6 +110,34 @@ cd <monorepo-root>
|
|
|
108
110
|
mico create subapp-react
|
|
109
111
|
```
|
|
110
112
|
|
|
113
|
+
## UMD 组件包生成器
|
|
114
|
+
|
|
115
|
+
在 Monorepo 的 `packages/` 目录下创建 UMD 格式的组件包,使用 Webpack 构建。适用于通过 `<script>` 标签加载的场景(如主应用菜单挂载组件、第三方系统嵌入 Widget 等)。
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
cd <monorepo-root>
|
|
119
|
+
mico create subapp-umd
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
生成器会提示输入:
|
|
123
|
+
- **Package name** — 包名(如 `my-widget`)
|
|
124
|
+
- **UMD global variable name** — 全局变量名(如 `MyWidget`)
|
|
125
|
+
- **Package scope** — 包作用域(自动从根 `package.json` 检测)
|
|
126
|
+
- **Dev server port** — 开发端口(默认 `9100`)
|
|
127
|
+
|
|
128
|
+
生成的包支持:
|
|
129
|
+
- `pnpm dev` — 启动 webpack-dev-server,同时提供 HTML 预览页和 UMD JS 文件
|
|
130
|
+
- `pnpm build` — 构建生产环境 UMD 产物到 `dist/`
|
|
131
|
+
|
|
132
|
+
开发模式下:
|
|
133
|
+
|
|
134
|
+
| URL | 用途 |
|
|
135
|
+
|---|---|
|
|
136
|
+
| `http://localhost:<port>/` | HTML 预览页,独立调试 |
|
|
137
|
+
| `http://localhost:<port>/<name>.umd.js` | UMD JS 文件,供主应用通过 `jsUrls` 联调 |
|
|
138
|
+
|
|
139
|
+
DevTools Sources 面板中可在 `webpack://<name>/src/` 下定位原始 TypeScript 源码进行断点调试。
|
|
140
|
+
|
|
111
141
|
## 本地调试
|
|
112
142
|
|
|
113
143
|
克隆项目后,执行以下步骤进行本地开发和调试:
|
|
@@ -133,6 +163,9 @@ mico create micro-react
|
|
|
133
163
|
|
|
134
164
|
# 测试 subapp-react 生成器(需在已有 monorepo 中执行)
|
|
135
165
|
mico create subapp-react
|
|
166
|
+
|
|
167
|
+
# 测试 subapp-umd 生成器(需在已有 monorepo 中执行)
|
|
168
|
+
mico create subapp-umd
|
|
136
169
|
```
|
|
137
170
|
|
|
138
171
|
调试完成后,可以取消全局链接:
|
package/bin/mico.js
CHANGED
|
@@ -29,12 +29,14 @@ Options:
|
|
|
29
29
|
--version, -v Show version number
|
|
30
30
|
--verbose Show detailed output during generation
|
|
31
31
|
--dry-run Preview files without creating them
|
|
32
|
+
--force Overwrite all existing files without confirmation
|
|
32
33
|
--no-update-check Skip update check
|
|
33
34
|
|
|
34
35
|
Examples:
|
|
35
36
|
mico create subapp-react
|
|
36
37
|
mico create micro-react --verbose
|
|
37
38
|
mico create micro-react --dry-run
|
|
39
|
+
mico create micro-react --force
|
|
38
40
|
mico list
|
|
39
41
|
mico update
|
|
40
42
|
mico doctor
|
|
@@ -350,6 +352,7 @@ function performUpdate(latestVersion) {
|
|
|
350
352
|
* @param {object} options - 选项
|
|
351
353
|
* @param {boolean} options.verbose - 是否启用详细输出
|
|
352
354
|
* @param {boolean} options.dryRun - 是否启用 dry-run 模式
|
|
355
|
+
* @param {boolean} options.force - 是否强制覆盖已有文件
|
|
353
356
|
*/
|
|
354
357
|
function runGenerator(generator, rest, passthroughArgs, options = {}) {
|
|
355
358
|
const localGeneratorEntry = path.join(
|
|
@@ -374,6 +377,10 @@ function runGenerator(generator, rest, passthroughArgs, options = {}) {
|
|
|
374
377
|
yoArgs.push('--dry-run');
|
|
375
378
|
}
|
|
376
379
|
|
|
380
|
+
if (options.force) {
|
|
381
|
+
yoArgs.push('--force');
|
|
382
|
+
}
|
|
383
|
+
|
|
377
384
|
if (passthroughArgs.length > 0) {
|
|
378
385
|
yoArgs.push('--', ...passthroughArgs);
|
|
379
386
|
}
|
|
@@ -394,6 +401,9 @@ function runGenerator(generator, rest, passthroughArgs, options = {}) {
|
|
|
394
401
|
if (options.dryRun) {
|
|
395
402
|
console.log(' \x1b[2m[verbose] Dry-run mode enabled\x1b[0m');
|
|
396
403
|
}
|
|
404
|
+
if (options.force) {
|
|
405
|
+
console.log(' \x1b[2m[verbose] Force mode enabled\x1b[0m');
|
|
406
|
+
}
|
|
397
407
|
console.log('');
|
|
398
408
|
}
|
|
399
409
|
|
|
@@ -432,6 +442,7 @@ async function main() {
|
|
|
432
442
|
const skipUpdateCheck = mainArgs.includes('--no-update-check');
|
|
433
443
|
const isVerbose = mainArgs.includes('--verbose');
|
|
434
444
|
const isDryRun = mainArgs.includes('--dry-run');
|
|
445
|
+
const isForce = mainArgs.includes('--force');
|
|
435
446
|
|
|
436
447
|
// 过滤掉标志参数
|
|
437
448
|
const filteredArgs = mainArgs.filter(
|
|
@@ -442,7 +453,8 @@ async function main() {
|
|
|
442
453
|
arg !== '-v' &&
|
|
443
454
|
arg !== '--no-update-check' &&
|
|
444
455
|
arg !== '--verbose' &&
|
|
445
|
-
arg !== '--dry-run'
|
|
456
|
+
arg !== '--dry-run' &&
|
|
457
|
+
arg !== '--force'
|
|
446
458
|
);
|
|
447
459
|
|
|
448
460
|
// 处理 --version
|
|
@@ -514,7 +526,8 @@ async function main() {
|
|
|
514
526
|
// 运行生成器
|
|
515
527
|
runGenerator(generator, rest.slice(1), passthroughArgs, {
|
|
516
528
|
verbose: isVerbose,
|
|
517
|
-
dryRun: isDryRun
|
|
529
|
+
dryRun: isDryRun,
|
|
530
|
+
force: isForce
|
|
518
531
|
});
|
|
519
532
|
return;
|
|
520
533
|
}
|
|
@@ -36,9 +36,9 @@ module.exports = class extends Generator {
|
|
|
36
36
|
this.logger.verbose('Config:', JSON.stringify(rcConfig, null, 2));
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
// 检查当前目录是否已是一个 monorepo
|
|
39
|
+
// 检查当前目录是否已是一个 monorepo(--force 跳过此检查)
|
|
40
40
|
const workspaceFile = path.join(this.projectRoot, 'pnpm-workspace.yaml');
|
|
41
|
-
if (fs.existsSync(workspaceFile)) {
|
|
41
|
+
if (fs.existsSync(workspaceFile) && !this.options.force) {
|
|
42
42
|
console.error('');
|
|
43
43
|
console.error('❌ Error: Current directory is already a monorepo.');
|
|
44
44
|
console.error('');
|
|
@@ -51,6 +51,9 @@ module.exports = class extends Generator {
|
|
|
51
51
|
console.error(' mkdir my-project && cd my-project');
|
|
52
52
|
console.error(' mico create micro-react');
|
|
53
53
|
console.error('');
|
|
54
|
+
console.error(' To regenerate in an existing monorepo, use --force:');
|
|
55
|
+
console.error(' mico create micro-react --force');
|
|
56
|
+
console.error('');
|
|
54
57
|
process.exit(1);
|
|
55
58
|
}
|
|
56
59
|
}
|
|
@@ -278,9 +281,31 @@ module.exports = class extends Generator {
|
|
|
278
281
|
|
|
279
282
|
this.log('');
|
|
280
283
|
this.log('📦 正在安装依赖...');
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
+
try {
|
|
285
|
+
this.spawnCommandSync('pnpm', ['install'], {
|
|
286
|
+
cwd: this.destDir,
|
|
287
|
+
});
|
|
288
|
+
} catch (e) {
|
|
289
|
+
this._installFailed = true;
|
|
290
|
+
this.log('');
|
|
291
|
+
this.log('⚠️ 依赖安装失败,但项目文件已全部生成。');
|
|
292
|
+
this.logger.verbose('Install error:', e.message);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 依赖安装成功后,格式化生成的文件以消除风格差异
|
|
297
|
+
const layoutDir = path.join(this.destDir, 'apps/layout');
|
|
298
|
+
if (fs.existsSync(path.join(layoutDir, '.prettierrc'))) {
|
|
299
|
+
this.log('');
|
|
300
|
+
this.log('🎨 格式化生成的文件...');
|
|
301
|
+
try {
|
|
302
|
+
this.spawnCommandSync('pnpm', ['-C', 'apps/layout', 'format'], {
|
|
303
|
+
cwd: this.destDir,
|
|
304
|
+
});
|
|
305
|
+
} catch (e) {
|
|
306
|
+
this.logger.verbose('Formatting failed (non-critical):', e.message);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
284
309
|
}
|
|
285
310
|
|
|
286
311
|
end() {
|
|
@@ -288,7 +313,20 @@ module.exports = class extends Generator {
|
|
|
288
313
|
if (this._skipInstall) return;
|
|
289
314
|
|
|
290
315
|
this.log('');
|
|
291
|
-
|
|
316
|
+
|
|
317
|
+
if (this._installFailed) {
|
|
318
|
+
this.log('⚠️ 项目文件已创建,但依赖安装未完成。');
|
|
319
|
+
this.log('');
|
|
320
|
+
this.log(' 请手动安装依赖:');
|
|
321
|
+
this.log('');
|
|
322
|
+
this.log(' pnpm install');
|
|
323
|
+
this.log('');
|
|
324
|
+
this.log(' 如果安装仍然失败,可尝试:');
|
|
325
|
+
this.log(' pnpm install --network-concurrency 4');
|
|
326
|
+
} else {
|
|
327
|
+
this.log('✅ 项目创建成功!');
|
|
328
|
+
}
|
|
329
|
+
|
|
292
330
|
this.log('');
|
|
293
331
|
this.log(' 后续步骤:');
|
|
294
332
|
this.log('');
|
|
@@ -34,11 +34,21 @@ fi
|
|
|
34
34
|
export CDN_PUBLIC_PATH="https://cdn-portal-dev.micoplatform.com/<%= cdnPrefixPath %><%= projectName %>/${VERSION}/"
|
|
35
35
|
echo "CDN_PUBLIC_PATH: $CDN_PUBLIC_PATH"
|
|
36
36
|
|
|
37
|
+
# 开发环境,不上传 sourcemap。调试时如有需要再解开
|
|
38
|
+
# # ========== Sentry Auth Token ==========
|
|
39
|
+
# # SENTRY_AUTH_TOKEN 从 Jenkins 服务器文件读取(敏感信息,不写在脚本中)
|
|
40
|
+
# SENTRY_TOKEN_FILE="/var/lib/jenkins/.portal_sentry_auth_token"
|
|
41
|
+
# if [ -f "$SENTRY_TOKEN_FILE" ]; then
|
|
42
|
+
# export SENTRY_AUTH_TOKEN=$(cat "$SENTRY_TOKEN_FILE")
|
|
43
|
+
# fi
|
|
44
|
+
|
|
45
|
+
# if [ -z "$SENTRY_AUTH_TOKEN" ]; then
|
|
46
|
+
# echo "警告:SENTRY_AUTH_TOKEN 未设置(文件 $SENTRY_TOKEN_FILE 不存在),跳过 sourcemap 上传"
|
|
47
|
+
# fi
|
|
48
|
+
|
|
37
49
|
pnpm run build:development
|
|
38
50
|
|
|
39
51
|
# 只有在 CI 环境时才写入版本号文件(覆盖写入)
|
|
40
52
|
if [ "${CI}" = "true" ]; then
|
|
41
53
|
echo "VERSION=$VERSION" > .env_x_<%= projectName %>
|
|
42
54
|
fi
|
|
43
|
-
|
|
44
|
-
|
|
@@ -34,10 +34,20 @@ fi
|
|
|
34
34
|
export CDN_PUBLIC_PATH="https://cdn-portal.micoplatform.com/<%= cdnPrefixPath %><%= projectName %>/${VERSION}/"
|
|
35
35
|
echo "CDN_PUBLIC_PATH: $CDN_PUBLIC_PATH"
|
|
36
36
|
|
|
37
|
+
# ========== Sentry Auth Token ==========
|
|
38
|
+
# SENTRY_AUTH_TOKEN 从 Jenkins 服务器文件读取(敏感信息,不写在脚本中)
|
|
39
|
+
SENTRY_TOKEN_FILE="/var/lib/jenkins/.portal_sentry_auth_token"
|
|
40
|
+
if [ -f "$SENTRY_TOKEN_FILE" ]; then
|
|
41
|
+
export SENTRY_AUTH_TOKEN=$(cat "$SENTRY_TOKEN_FILE")
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
if [ -z "$SENTRY_AUTH_TOKEN" ]; then
|
|
45
|
+
echo "警告:SENTRY_AUTH_TOKEN 未设置(文件 $SENTRY_TOKEN_FILE 不存在),跳过 sourcemap 上传"
|
|
46
|
+
fi
|
|
47
|
+
|
|
37
48
|
pnpm run build:production
|
|
38
49
|
|
|
39
50
|
# 只有在 CI 环境时才写入版本号文件(覆盖写入)
|
|
40
51
|
if [ "${CI}" = "true" ]; then
|
|
41
52
|
echo "VERSION=$VERSION" > .env_x_<%= projectName %>
|
|
42
53
|
fi
|
|
43
|
-
|
|
@@ -35,10 +35,21 @@ fi
|
|
|
35
35
|
export CDN_PUBLIC_PATH="https://cdn-portal-test.micoplatform.com/<%= cdnPrefixPath %><%= projectName %>/${VERSION}/"
|
|
36
36
|
echo "CDN_PUBLIC_PATH: $CDN_PUBLIC_PATH"
|
|
37
37
|
|
|
38
|
+
# 测试环境,不上传 sourcemap。调试时如有需要再解开
|
|
39
|
+
# # ========== Sentry Auth Token ==========
|
|
40
|
+
# # SENTRY_AUTH_TOKEN 从 Jenkins 服务器文件读取(敏感信息,不写在脚本中)
|
|
41
|
+
# SENTRY_TOKEN_FILE="/var/lib/jenkins/.portal_sentry_auth_token"
|
|
42
|
+
# if [ -f "$SENTRY_TOKEN_FILE" ]; then
|
|
43
|
+
# export SENTRY_AUTH_TOKEN=$(cat "$SENTRY_TOKEN_FILE")
|
|
44
|
+
# fi
|
|
45
|
+
|
|
46
|
+
# if [ -z "$SENTRY_AUTH_TOKEN" ]; then
|
|
47
|
+
# echo "警告:SENTRY_AUTH_TOKEN 未设置(文件 $SENTRY_TOKEN_FILE 不存在),跳过 sourcemap 上传"
|
|
48
|
+
# fi
|
|
49
|
+
|
|
38
50
|
pnpm run build:testing
|
|
39
51
|
|
|
40
52
|
# 只有在 CI 环境时才写入版本号文件(覆盖写入)
|
|
41
53
|
if [ "${CI}" = "true" ]; then
|
|
42
54
|
echo "VERSION=$VERSION" > .env_x_<%= projectName %>
|
|
43
55
|
fi
|
|
44
|
-
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
registry=https://registry.npmjs.com/
|
|
2
2
|
@mico-platform:registry=https://nexus-vywrajy.micoworld.net/repository/mico-base-common/
|
|
3
|
+
@common-web:registry=https://nexus-vywrajy.micoworld.net/repository/mico-base-common/
|
|
3
4
|
package-lock=false
|
|
4
5
|
//nexus-vywrajy.micoworld.net/repository/mico-base-common/:_auth=bWljby1ucG06SDR4WUROazdad1NeczltblJMTw==
|
|
5
6
|
|
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
// https://umijs.org/config/
|
|
2
2
|
|
|
3
3
|
import { defineConfig } from '@umijs/max';
|
|
4
|
+
// 开发环境,不上传 sourcemap。调试时如有需要再解开
|
|
5
|
+
// import { applySentryPlugin } from "../../../scripts/apply-sentry-plugin";
|
|
4
6
|
|
|
5
7
|
const config: ReturnType<typeof defineConfig> = {
|
|
8
|
+
// 开发环境,不上传 sourcemap。调试时如有需要再解开
|
|
9
|
+
// devtool: 'hidden-source-map',
|
|
10
|
+
|
|
11
|
+
// chainWebpack(memo) {
|
|
12
|
+
// // 开发环境,不上传 sourcemap。调试时如有需要再解开
|
|
13
|
+
// applySentryPlugin({ memo, appName: 'layout' });
|
|
14
|
+
// return memo;
|
|
15
|
+
// },
|
|
16
|
+
|
|
17
|
+
externals: {
|
|
18
|
+
react: 'React',
|
|
19
|
+
'react-dom': 'ReactDOM',
|
|
20
|
+
'@common-web/sentry': 'CommonWebSentry',
|
|
21
|
+
},
|
|
6
22
|
define: {
|
|
7
23
|
'process.env.NODE_ENV': 'development',
|
|
8
24
|
'process.env.APP_ID': '<%= projectName %>',
|
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
// https://umijs.org/config/
|
|
2
2
|
|
|
3
3
|
import { defineConfig } from '@umijs/max';
|
|
4
|
+
// 测试环境,不上传 sourcemap。调试时如有需要再解开
|
|
5
|
+
// import { applySentryPlugin } from "../../../scripts/apply-sentry-plugin";
|
|
4
6
|
|
|
5
7
|
const config: ReturnType<typeof defineConfig> = {
|
|
8
|
+
// 测试环境,不上传 sourcemap。调试时如有需要再解开
|
|
9
|
+
// devtool: 'hidden-source-map',
|
|
10
|
+
|
|
11
|
+
// chainWebpack(memo) {
|
|
12
|
+
// // 测试环境,不上传 sourcemap。调试时如有需要再解开
|
|
13
|
+
// applySentryPlugin({ memo, appName: 'layout' });
|
|
14
|
+
// return memo;
|
|
15
|
+
// },
|
|
16
|
+
|
|
17
|
+
externals: {
|
|
18
|
+
react: 'React',
|
|
19
|
+
'react-dom': 'ReactDOM',
|
|
20
|
+
'@common-web/sentry': 'CommonWebSentry',
|
|
21
|
+
},
|
|
6
22
|
define: {
|
|
7
23
|
'process.env.NODE_ENV': 'testing',
|
|
8
24
|
'process.env.APP_ID': '<%= projectName %>',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// https://umijs.org/config/
|
|
2
2
|
|
|
3
3
|
import { defineConfig } from '@umijs/max';
|
|
4
|
+
import { applySentryPlugin } from '../../../scripts/apply-sentry-plugin';
|
|
4
5
|
const { CDN_PUBLIC_PATH } = process.env;
|
|
5
6
|
|
|
6
7
|
const PUBLIC_PATH: string = CDN_PUBLIC_PATH
|
|
@@ -8,6 +9,11 @@ const PUBLIC_PATH: string = CDN_PUBLIC_PATH
|
|
|
8
9
|
: '/layout/';
|
|
9
10
|
|
|
10
11
|
const config: ReturnType<typeof defineConfig> = {
|
|
12
|
+
/**
|
|
13
|
+
* 启用 Source Map(用于 Sentry 错误追踪)
|
|
14
|
+
* hidden-source-map 会生成 .map 文件但不在 JS 中添加 sourcemap 注释
|
|
15
|
+
*/
|
|
16
|
+
devtool: 'hidden-source-map',
|
|
11
17
|
define: {
|
|
12
18
|
'process.env.NODE_ENV': 'production',
|
|
13
19
|
'process.env.APP_ID': '<%= projectName %>',
|
|
@@ -20,6 +26,11 @@ const config: ReturnType<typeof defineConfig> = {
|
|
|
20
26
|
'process.env.EXTERNAL_LOGIN_PATH':
|
|
21
27
|
'https://micous-idp.cig.tencentcs.com/sso/xxxxxxx/cas',
|
|
22
28
|
},
|
|
29
|
+
externals: {
|
|
30
|
+
react: 'React',
|
|
31
|
+
'react-dom': 'ReactDOM',
|
|
32
|
+
'@common-web/sentry': 'CommonWebSentry',
|
|
33
|
+
},
|
|
23
34
|
// 生产环境:将所有代码打包到一个文件
|
|
24
35
|
extraBabelPlugins: ['babel-plugin-dynamic-import-node'],
|
|
25
36
|
|
|
@@ -29,6 +40,7 @@ const config: ReturnType<typeof defineConfig> = {
|
|
|
29
40
|
memo.optimization.splitChunks(false);
|
|
30
41
|
// 禁用 runtimeChunk
|
|
31
42
|
memo.optimization.runtimeChunk(false);
|
|
43
|
+
applySentryPlugin({ memo, appName: 'layout' });
|
|
32
44
|
return memo;
|
|
33
45
|
},
|
|
34
46
|
publicPath: PUBLIC_PATH,
|
|
@@ -64,12 +64,13 @@
|
|
|
64
64
|
└──────────────────────────────────────────┘
|
|
65
65
|
│
|
|
66
66
|
▼
|
|
67
|
-
|
|
68
|
-
│ 3. 菜单渲染 (menu/index.tsx)
|
|
69
|
-
│
|
|
70
|
-
│
|
|
71
|
-
│
|
|
72
|
-
|
|
67
|
+
┌──────────────────────────────────────────┐
|
|
68
|
+
│ 3. 菜单渲染 (menu/index.tsx) │
|
|
69
|
+
│ 按 side_menus 过滤 │
|
|
70
|
+
│ 每个菜单项独立检查 isNoPermissionRoute│
|
|
71
|
+
│ ├── 匹配 → 该项始终显示 │
|
|
72
|
+
│ └── 不匹配 → 按 sideMenus 白名单过滤 │
|
|
73
|
+
└──────────────────────────────────────────┘
|
|
73
74
|
│
|
|
74
75
|
▼
|
|
75
76
|
┌──────────────────────────────────────────────┐
|
|
@@ -99,7 +100,7 @@ page.accessControlEnabled === false?
|
|
|
99
100
|
│
|
|
100
101
|
▼
|
|
101
102
|
是否在 noPermissionRouteList 中?
|
|
102
|
-
├── 是 →
|
|
103
|
+
├── 是 → 允许访问,菜单按各项独立判断
|
|
103
104
|
│
|
|
104
105
|
▼
|
|
105
106
|
是否是非动态路由(不在 PAGES 中)?
|
|
@@ -344,7 +345,7 @@ if (!isAuthReady) {
|
|
|
344
345
|
| 403 处理 | 原地渲染组件 | 保持 URL 不变,用户体验更好,便于分享链接 |
|
|
345
346
|
| 父级菜单显示 | 前缀匹配 | 子菜单有权限时,父级菜单需要作为容器显示 |
|
|
346
347
|
| 超级用户 | 跳过所有检查 | 管理员需要完整访问权限 |
|
|
347
|
-
| 免权限路由的菜单 |
|
|
348
|
+
| 免权限路由的菜单 | 按菜单项独立判断 | 每个菜单项根据自身路由是否匹配 noPermissionRouteList 独立决定显示,避免菜单随当前页面变化 |
|
|
348
349
|
| 免认证路由的子应用 | 直接加载 | 不等待 currentUser,免认证路由本身不需要登录 |
|
|
349
350
|
| 免权限路由的子应用 | 直接加载 | 不等待 currentUser,避免加载卡住 |
|
|
350
351
|
| 静态路由不受权限控制 | 默认允许访问 | 见下方"静态路由与动态路由"说明 |
|
|
@@ -6,73 +6,93 @@
|
|
|
6
6
|
|
|
7
7
|
export default {
|
|
8
8
|
// 获取用户信息
|
|
9
|
-
|
|
9
|
+
'GET /api/user/info': {
|
|
10
|
+
"code": 200,
|
|
11
|
+
"data": {
|
|
12
|
+
"id": 381,
|
|
13
|
+
"last_login": "2026-03-06T02:37:10.050735Z",
|
|
14
|
+
"is_superuser": true,
|
|
15
|
+
"username": "本地测试mock用户",
|
|
16
|
+
"first_name": "",
|
|
17
|
+
"last_name": "",
|
|
18
|
+
"email": "本地测试mock用户@micous.com",
|
|
19
|
+
"is_staff": true,
|
|
20
|
+
"is_active": true,
|
|
21
|
+
"type": 1,
|
|
22
|
+
"phone": "",
|
|
23
|
+
"agency_id": 0,
|
|
24
|
+
"avatar": "https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png",
|
|
25
|
+
"user_name": "Easton",
|
|
26
|
+
"permission_tree": [
|
|
27
|
+
],
|
|
28
|
+
"miss_permissions": [],
|
|
29
|
+
"side_menus": [
|
|
30
|
+
'首页',
|
|
31
|
+
'示例模块.示例页面',
|
|
32
|
+
'微应用示例.子应用页面',
|
|
33
|
+
'外部链接',
|
|
34
|
+
'权限管理',
|
|
35
|
+
],
|
|
36
|
+
"region_permissions": []
|
|
37
|
+
},
|
|
38
|
+
"msg": "ok"
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
// 获取统计数据
|
|
42
|
+
// 'GET /api/dashboard/stats': {
|
|
10
43
|
// success: true,
|
|
11
44
|
// data: {
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
// department: '技术部',
|
|
45
|
+
// totalUsers: 12580,
|
|
46
|
+
// activeUsers: 3420,
|
|
47
|
+
// pendingTasks: 156,
|
|
48
|
+
// completedTasks: 8934,
|
|
49
|
+
// lastUpdated: new Date().toISOString(),
|
|
18
50
|
// },
|
|
19
51
|
// },
|
|
20
52
|
|
|
21
|
-
// 获取统计数据
|
|
22
|
-
'GET /api/dashboard/stats': {
|
|
23
|
-
success: true,
|
|
24
|
-
data: {
|
|
25
|
-
totalUsers: 12580,
|
|
26
|
-
activeUsers: 3420,
|
|
27
|
-
pendingTasks: 156,
|
|
28
|
-
completedTasks: 8934,
|
|
29
|
-
lastUpdated: new Date().toISOString(),
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
|
|
33
53
|
// 获取列表数据
|
|
34
|
-
'GET /api/items': {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
},
|
|
54
|
+
// 'GET /api/items': {
|
|
55
|
+
// success: true,
|
|
56
|
+
// data: {
|
|
57
|
+
// list: [
|
|
58
|
+
// {
|
|
59
|
+
// id: 1,
|
|
60
|
+
// title: '待审核内容 A',
|
|
61
|
+
// status: 'pending',
|
|
62
|
+
// createdAt: '2025-12-27 10:00:00',
|
|
63
|
+
// },
|
|
64
|
+
// {
|
|
65
|
+
// id: 2,
|
|
66
|
+
// title: '待审核内容 B',
|
|
67
|
+
// status: 'pending',
|
|
68
|
+
// createdAt: '2025-12-27 09:30:00',
|
|
69
|
+
// },
|
|
70
|
+
// {
|
|
71
|
+
// id: 3,
|
|
72
|
+
// title: '已通过内容 C',
|
|
73
|
+
// status: 'approved',
|
|
74
|
+
// createdAt: '2025-12-26 15:00:00',
|
|
75
|
+
// },
|
|
76
|
+
// {
|
|
77
|
+
// id: 4,
|
|
78
|
+
// title: '已拒绝内容 D',
|
|
79
|
+
// status: 'rejected',
|
|
80
|
+
// createdAt: '2025-12-26 14:00:00',
|
|
81
|
+
// },
|
|
82
|
+
// ],
|
|
83
|
+
// total: 4,
|
|
84
|
+
// page: 1,
|
|
85
|
+
// pageSize: 10,
|
|
86
|
+
// },
|
|
87
|
+
// },
|
|
68
88
|
|
|
69
89
|
// POST 请求示例
|
|
70
|
-
'POST /api/items/approve': (req: any, res: any) => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
},
|
|
90
|
+
// 'POST /api/items/approve': (req: any, res: any) => {
|
|
91
|
+
// const { id } = req.body || {};
|
|
92
|
+
// res.json({
|
|
93
|
+
// success: true,
|
|
94
|
+
// message: `Item ${id} approved successfully`,
|
|
95
|
+
// data: { id, status: 'approved' },
|
|
96
|
+
// });
|
|
97
|
+
// },
|
|
78
98
|
};
|
|
@@ -29,7 +29,7 @@ const mockPages: PublicPageItem[] = [
|
|
|
29
29
|
nameKey: 'page.user.login',
|
|
30
30
|
route: '/user/login',
|
|
31
31
|
htmlUrl:
|
|
32
|
-
'https://cdn-portal.micoplatform.com/portal-center/common-web/0.0.
|
|
32
|
+
'https://cdn-portal.micoplatform.com/portal-center/common-web/0.0.4/login/index.html',
|
|
33
33
|
jsUrls: [],
|
|
34
34
|
cssUrls: [],
|
|
35
35
|
prefixPath: '/user',
|
|
@@ -48,7 +48,7 @@ const mockPages: PublicPageItem[] = [
|
|
|
48
48
|
nameKey: 'page.permission',
|
|
49
49
|
route: '/permission',
|
|
50
50
|
htmlUrl:
|
|
51
|
-
'https://cdn-portal.micoplatform.com/portal-center/common-web/0.0.
|
|
51
|
+
'https://cdn-portal.micoplatform.com/portal-center/common-web/0.0.4/permission/index.html',
|
|
52
52
|
jsUrls: [],
|
|
53
53
|
cssUrls: [],
|
|
54
54
|
prefixPath: '',
|
|
@@ -72,7 +72,7 @@ const mockPages: PublicPageItem[] = [
|
|
|
72
72
|
prefixPath: '',
|
|
73
73
|
routeMode: 'prefix',
|
|
74
74
|
enabled: true,
|
|
75
|
-
accessControlEnabled:
|
|
75
|
+
accessControlEnabled: true,
|
|
76
76
|
adminOnly: false,
|
|
77
77
|
routeKey: null,
|
|
78
78
|
mainDocumentId: 59,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { history, type RequestConfig } from '@umijs/max';
|
|
2
2
|
import { addGlobalUncaughtErrorHandler } from 'qiankun';
|
|
3
|
+
import { SentryErrorBoundary } from '@common-web/sentry';
|
|
3
4
|
import { errorConfig } from './requestErrorConfig';
|
|
4
5
|
// 将 @mico-platform/ui 暴露到 window,供子应用 externals 使用
|
|
5
6
|
import * as micoUI from '@mico-platform/ui';
|
|
6
7
|
import React from 'react';
|
|
7
8
|
import ReactDOM from 'react-dom';
|
|
8
|
-
import ReactDOMClient from 'react-dom/client';
|
|
9
9
|
|
|
10
10
|
import { getStoredAuthToken } from './common/auth/auth-manager';
|
|
11
11
|
import type { IUserInfo } from './common/auth/type';
|
|
@@ -88,7 +88,6 @@ if (typeof window !== 'undefined') {
|
|
|
88
88
|
const win = window as unknown as Record<string, unknown>;
|
|
89
89
|
win.React = React;
|
|
90
90
|
win.ReactDOM = ReactDOM;
|
|
91
|
-
win.ReactDOMClient = ReactDOMClient;
|
|
92
91
|
win.micoUI = micoUI;
|
|
93
92
|
}
|
|
94
93
|
|
|
@@ -172,6 +171,10 @@ export const request: RequestConfig = {
|
|
|
172
171
|
...errorConfig,
|
|
173
172
|
};
|
|
174
173
|
|
|
174
|
+
export function rootContainer(container: React.ReactNode) {
|
|
175
|
+
return <SentryErrorBoundary>{container}</SentryErrorBoundary>;
|
|
176
|
+
}
|
|
177
|
+
|
|
175
178
|
/**
|
|
176
179
|
* Umi 路由类型定义
|
|
177
180
|
*/
|