generator-mico-cli 0.1.0
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 +65 -0
- package/bin/mico.js +81 -0
- package/generators/subapp-react/ignore-list.json +7 -0
- package/generators/subapp-react/index.js +131 -0
- package/generators/subapp-react/templates/homepage/.env +4 -0
- package/generators/subapp-react/templates/homepage/config/config.dev.ts +50 -0
- package/generators/subapp-react/templates/homepage/config/config.prod.ts +41 -0
- package/generators/subapp-react/templates/homepage/config/config.testing.ts +8 -0
- package/generators/subapp-react/templates/homepage/config/config.ts +102 -0
- package/generators/subapp-react/templates/homepage/config/routes.ts +7 -0
- package/generators/subapp-react/templates/homepage/mock/api.mock.ts +59 -0
- package/generators/subapp-react/templates/homepage/package.json +30 -0
- package/generators/subapp-react/templates/homepage/src/app.tsx +80 -0
- package/generators/subapp-react/templates/homepage/src/assets/yay.jpg +0 -0
- package/generators/subapp-react/templates/homepage/src/common/logger.ts +42 -0
- package/generators/subapp-react/templates/homepage/src/common/mainApp.ts +53 -0
- package/generators/subapp-react/templates/homepage/src/common/request.ts +49 -0
- package/generators/subapp-react/templates/homepage/src/global.less +26 -0
- package/generators/subapp-react/templates/homepage/src/pages/index.less +139 -0
- package/generators/subapp-react/templates/homepage/src/pages/index.tsx +342 -0
- package/generators/subapp-react/templates/homepage/src/styles/theme.less +6 -0
- package/generators/subapp-react/templates/homepage/tsconfig.json +3 -0
- package/generators/subapp-react/templates/homepage/typings.d.ts +17 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Mico CLI Generator
|
|
2
|
+
|
|
3
|
+
用于搭建基于 TypeScript 的 Node.js CLI 项目的 Yeoman 生成器。
|
|
4
|
+
|
|
5
|
+
## 文档索引
|
|
6
|
+
|
|
7
|
+
- `docs/subapp-react-generator.md` React 子应用生成器说明
|
|
8
|
+
|
|
9
|
+
## 要求
|
|
10
|
+
|
|
11
|
+
- Node >= 18
|
|
12
|
+
- Yeoman CLI: `npm install -g yo`
|
|
13
|
+
|
|
14
|
+
## 安装和使用
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -g yo generator-mico-cli
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 包装器 CLI
|
|
21
|
+
|
|
22
|
+
全局安装后,`mico` 命令可用于委托给 Yeoman 生成器。
|
|
23
|
+
如果 `generators/<name>` 下存在本地生成器,它将作为 `yo mico-cli:<name>` 运行。
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
mico create subapp-react
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
等同于:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
yo subapp-react
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
将额外参数传递给生成器:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
mico create mirco-react -- --help
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## React 子应用生成器(audit-center)
|
|
42
|
+
|
|
43
|
+
该生成器会复制 `apps/homepage` 为新的子应用,并替换标识字符串。
|
|
44
|
+
`config/` 目录下的多环境配置会完整保留。
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
cd <monorepo-root>
|
|
48
|
+
mico create subapp-react
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 同步子应用模板
|
|
52
|
+
|
|
53
|
+
将 `audit-center/apps/homepage` 同步到生成器模板目录:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
AUDIT_CENTER_ROOT=<audit-center-root> npm run sync:subapp-react-template
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
也可以直接传入路径:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm run sync:subapp-react-template -- <audit-center-root>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
忽略清单位于 `generators/subapp-react/ignore-list.json`。
|
package/bin/mico.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { spawn } = require('node:child_process');
|
|
5
|
+
const fs = require('node:fs');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
|
|
8
|
+
function printHelp() {
|
|
9
|
+
console.log('Usage: mico create <generator> [args]');
|
|
10
|
+
console.log(' mico create <generator> -- [args]');
|
|
11
|
+
console.log('');
|
|
12
|
+
console.log('Examples:');
|
|
13
|
+
console.log(' mico create mirco-react');
|
|
14
|
+
console.log(' mico create mico-cli -- --help');
|
|
15
|
+
console.log('');
|
|
16
|
+
console.log('Notes:');
|
|
17
|
+
console.log(' Requires Yeoman CLI (yo) installed globally.');
|
|
18
|
+
console.log(' If a local generator exists at generators/<name>, it will be used.');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const args = process.argv.slice(2);
|
|
22
|
+
const doubleDashIndex = args.indexOf('--');
|
|
23
|
+
const passthroughArgs =
|
|
24
|
+
doubleDashIndex === -1 ? [] : args.slice(doubleDashIndex + 1);
|
|
25
|
+
const mainArgs = doubleDashIndex === -1 ? args : args.slice(0, doubleDashIndex);
|
|
26
|
+
const hasHelp = mainArgs.includes('--help') || mainArgs.includes('-h');
|
|
27
|
+
|
|
28
|
+
if (mainArgs.length === 0 || hasHelp) {
|
|
29
|
+
printHelp();
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const [command, generator, ...rest] = mainArgs;
|
|
34
|
+
|
|
35
|
+
if (command !== 'create' || !generator) {
|
|
36
|
+
printHelp();
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const rootDir = path.resolve(__dirname, '..');
|
|
41
|
+
const localGeneratorEntry = path.join(
|
|
42
|
+
rootDir,
|
|
43
|
+
'generators',
|
|
44
|
+
generator,
|
|
45
|
+
'index.js'
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
let localNamespace = 'generator';
|
|
49
|
+
try {
|
|
50
|
+
const pkg = JSON.parse(
|
|
51
|
+
fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8')
|
|
52
|
+
);
|
|
53
|
+
const pkgName = typeof pkg.name === 'string' ? pkg.name : '';
|
|
54
|
+
localNamespace = pkgName.replace(/^generator-/, '') || pkgName || localNamespace;
|
|
55
|
+
} catch {
|
|
56
|
+
// Fall back to a generic namespace
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const yoGenerator = fs.existsSync(localGeneratorEntry)
|
|
60
|
+
? `${localNamespace}:${generator}`
|
|
61
|
+
: generator;
|
|
62
|
+
const yoArgs = [yoGenerator, ...rest];
|
|
63
|
+
|
|
64
|
+
if (passthroughArgs.length > 0) {
|
|
65
|
+
yoArgs.push('--', ...passthroughArgs);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const child = spawn('yo', yoArgs, { stdio: 'inherit' });
|
|
69
|
+
|
|
70
|
+
child.on('error', (error) => {
|
|
71
|
+
if (error && error.code === 'ENOENT') {
|
|
72
|
+
console.error('Cannot find "yo". Install it with: npm install -g yo');
|
|
73
|
+
} else {
|
|
74
|
+
console.error(error);
|
|
75
|
+
}
|
|
76
|
+
process.exit(1);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
child.on('exit', (code) => {
|
|
80
|
+
process.exit(typeof code === 'number' ? code : 1);
|
|
81
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Generator = require('yeoman-generator');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const { toKebab, toPascal } = require('../../lib/utils');
|
|
7
|
+
|
|
8
|
+
const IGNORE_LIST = require('./ignore-list.json');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 检查路径是否应该被忽略
|
|
12
|
+
*/
|
|
13
|
+
function shouldIgnorePath(sourceRoot, currentPath) {
|
|
14
|
+
const rel = path.relative(sourceRoot, currentPath);
|
|
15
|
+
if (!rel || rel.startsWith('..')) return false;
|
|
16
|
+
const parts = rel.split(path.sep);
|
|
17
|
+
return parts.some((part) => IGNORE_LIST.includes(part));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 递归遍历目录,收集所有文件的相对路径
|
|
22
|
+
*/
|
|
23
|
+
function collectFiles(dir, sourceRoot, files = []) {
|
|
24
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
25
|
+
const fullPath = path.join(dir, entry.name);
|
|
26
|
+
if (shouldIgnorePath(sourceRoot, fullPath)) continue;
|
|
27
|
+
|
|
28
|
+
if (entry.isDirectory()) {
|
|
29
|
+
collectFiles(fullPath, sourceRoot, files);
|
|
30
|
+
} else if (entry.isFile()) {
|
|
31
|
+
files.push(path.relative(sourceRoot, fullPath));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return files;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 需要使用 EJS 模板处理的文件扩展名
|
|
39
|
+
*/
|
|
40
|
+
const TEMPLATE_EXTENSIONS = new Set([
|
|
41
|
+
'.ts',
|
|
42
|
+
'.tsx',
|
|
43
|
+
'.js',
|
|
44
|
+
'.jsx',
|
|
45
|
+
'.json',
|
|
46
|
+
'.less',
|
|
47
|
+
'.md'
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
module.exports = class extends Generator {
|
|
51
|
+
async prompting() {
|
|
52
|
+
this.answers = await this.prompt([
|
|
53
|
+
{
|
|
54
|
+
type: 'input',
|
|
55
|
+
name: 'appName',
|
|
56
|
+
message: 'Sub app name',
|
|
57
|
+
default: 'subapp',
|
|
58
|
+
filter: (input) => toKebab(input),
|
|
59
|
+
validate: (input) => {
|
|
60
|
+
const value = toKebab(input);
|
|
61
|
+
if (!value) return 'App name is required';
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
this.monorepoRoot = this.destinationRoot();
|
|
68
|
+
this.appName = toKebab(this.answers.appName);
|
|
69
|
+
this.appNamePascal = toPascal(this.appName);
|
|
70
|
+
this.templateDir = this.templatePath('homepage');
|
|
71
|
+
this.destDir = path.join(this.monorepoRoot, 'apps', this.appName);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
writing() {
|
|
75
|
+
const appsDir = path.join(this.monorepoRoot, 'apps');
|
|
76
|
+
const workspaceFile = path.join(this.monorepoRoot, 'pnpm-workspace.yaml');
|
|
77
|
+
|
|
78
|
+
// 检查是否在 monorepo 中
|
|
79
|
+
if (!fs.existsSync(appsDir)) {
|
|
80
|
+
this.env.error(
|
|
81
|
+
`apps directory not found in ${this.monorepoRoot}. Run this generator from the monorepo root.`
|
|
82
|
+
);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 警告:检查是否是 pnpm workspace
|
|
87
|
+
if (!fs.existsSync(workspaceFile)) {
|
|
88
|
+
this.log.warning(
|
|
89
|
+
'pnpm-workspace.yaml not found. Make sure you are in the correct monorepo.'
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (fs.existsSync(this.destDir)) {
|
|
94
|
+
this.env.error(`Target already exists: ${this.destDir}`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 模板数据
|
|
99
|
+
const templateData = {
|
|
100
|
+
appName: this.appName,
|
|
101
|
+
AppName: this.appNamePascal
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// 收集所有文件
|
|
105
|
+
const files = collectFiles(this.templateDir, this.templateDir);
|
|
106
|
+
|
|
107
|
+
for (const relPath of files) {
|
|
108
|
+
const srcPath = path.join(this.templateDir, relPath);
|
|
109
|
+
const destPath = path.join(this.destDir, relPath);
|
|
110
|
+
const ext = path.extname(relPath);
|
|
111
|
+
|
|
112
|
+
if (TEMPLATE_EXTENSIONS.has(ext)) {
|
|
113
|
+
// 使用 EJS 模板处理
|
|
114
|
+
this.fs.copyTpl(srcPath, destPath, templateData);
|
|
115
|
+
} else {
|
|
116
|
+
// 直接复制(图片等二进制文件)
|
|
117
|
+
this.fs.copy(srcPath, destPath);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
end() {
|
|
123
|
+
this.log('');
|
|
124
|
+
this.log('✅ 子应用创建成功!');
|
|
125
|
+
this.log('');
|
|
126
|
+
this.log(` cd apps/${this.appName}`);
|
|
127
|
+
this.log(' pnpm install');
|
|
128
|
+
this.log(' pnpm dev');
|
|
129
|
+
this.log('');
|
|
130
|
+
}
|
|
131
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// https://umijs.org/config/
|
|
2
|
+
|
|
3
|
+
import { defineConfig } from '@umijs/max';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 开发环境配置
|
|
7
|
+
* - 不配置 externals,直接打包依赖,方便独立运行调试
|
|
8
|
+
* - 生产环境通过 config.prod.ts 配置 externals 复用主应用依赖
|
|
9
|
+
*/
|
|
10
|
+
const config: ReturnType<typeof defineConfig> = {
|
|
11
|
+
publicPath: '/',
|
|
12
|
+
base: '/',
|
|
13
|
+
|
|
14
|
+
define: {
|
|
15
|
+
'process.env.NODE_ENV': 'development',
|
|
16
|
+
},
|
|
17
|
+
// /**
|
|
18
|
+
// * @name 脚本加载配置
|
|
19
|
+
// * @description 开发环境独立运行时,通过 CDN 加载公共依赖
|
|
20
|
+
// * 作为微前端子应用运行时,这些库由主应用提供
|
|
21
|
+
// */
|
|
22
|
+
// headScripts: [
|
|
23
|
+
// 'https://unpkg.com/react@18/umd/react.development.js',
|
|
24
|
+
// 'https://unpkg.com/react-dom@18/umd/react-dom.development.js',
|
|
25
|
+
// 'https://unpkg.com/@arco-design/web-react@latest/dist/arco.min.js',
|
|
26
|
+
// ],
|
|
27
|
+
|
|
28
|
+
// /**
|
|
29
|
+
// * @name 样式加载配置
|
|
30
|
+
// * @description 开发环境独立运行时加载 Arco Design CSS
|
|
31
|
+
// */
|
|
32
|
+
// links: [
|
|
33
|
+
// {
|
|
34
|
+
// rel: 'stylesheet',
|
|
35
|
+
// href: 'https://unpkg.com/@arco-design/web-react@latest/dist/css/arco.min.css',
|
|
36
|
+
// },
|
|
37
|
+
// ],
|
|
38
|
+
|
|
39
|
+
// /**
|
|
40
|
+
// * @name 外部依赖配置
|
|
41
|
+
// * @description 开发环境也需要 externals,配合 CDN 使用
|
|
42
|
+
// */
|
|
43
|
+
// externals: {
|
|
44
|
+
// react: 'window.React',
|
|
45
|
+
// 'react-dom': 'window.ReactDOM',
|
|
46
|
+
// '@arco-design/web-react': 'window.arco',
|
|
47
|
+
// },
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default defineConfig(config);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// https://umijs.org/config/
|
|
2
|
+
|
|
3
|
+
import { defineConfig } from '@umijs/max';
|
|
4
|
+
const { CDN_PUBLIC_PATH } = process.env;
|
|
5
|
+
|
|
6
|
+
const PUBLIC_PATH: string = CDN_PUBLIC_PATH
|
|
7
|
+
? `${CDN_PUBLIC_PATH.replace(/\/?$/, '/') }homepage/`
|
|
8
|
+
: '/homepage/';
|
|
9
|
+
|
|
10
|
+
const config: ReturnType<typeof defineConfig> = {
|
|
11
|
+
// 生产环境:将所有代码打包到一个文件
|
|
12
|
+
extraBabelPlugins: ['babel-plugin-dynamic-import-node'],
|
|
13
|
+
|
|
14
|
+
// 禁用代码分割,只输出一个 JS 和一个 CSS
|
|
15
|
+
chainWebpack(memo) {
|
|
16
|
+
// 禁用 splitChunks
|
|
17
|
+
memo.optimization.splitChunks(false);
|
|
18
|
+
// 禁用 runtimeChunk
|
|
19
|
+
memo.optimization.runtimeChunk(false);
|
|
20
|
+
return memo;
|
|
21
|
+
},
|
|
22
|
+
publicPath: PUBLIC_PATH,
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @name 外部依赖配置
|
|
27
|
+
* @description 将大型公共库排除打包,运行时从主应用获取
|
|
28
|
+
* @doc https://umijs.org/docs/api/config#externals
|
|
29
|
+
*
|
|
30
|
+
* 作为 qiankun 子应用时,这些库由主应用提供:
|
|
31
|
+
* - react / react-dom: 主应用已加载,避免多实例问题
|
|
32
|
+
* - @arco-design/web-react: 主应用已加载,复用组件和样式
|
|
33
|
+
*/
|
|
34
|
+
externals: {
|
|
35
|
+
react: 'window.React',
|
|
36
|
+
'react-dom': 'window.ReactDOM',
|
|
37
|
+
'@arco-design/web-react': 'window.arco',
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default defineConfig(config);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// https://umijs.org/config/
|
|
2
|
+
|
|
3
|
+
import { defineConfig } from '@umijs/max';
|
|
4
|
+
import routes from './routes';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @name 使用公共路径
|
|
8
|
+
* @description 部署时的路径
|
|
9
|
+
*/
|
|
10
|
+
const PUBLIC_PATH = '/dist/<%= appName %>/';
|
|
11
|
+
|
|
12
|
+
const config: ReturnType<typeof defineConfig> = {
|
|
13
|
+
/**
|
|
14
|
+
* @name 挂载元素 ID
|
|
15
|
+
* @description React 应用挂载的 DOM 元素 id
|
|
16
|
+
*/
|
|
17
|
+
mountElementId: '<%= appName %>-root',
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @name 基础路径
|
|
21
|
+
* @description 子应用的路由前缀
|
|
22
|
+
*/
|
|
23
|
+
base: '/',
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @name 开启 hash 模式
|
|
27
|
+
* @description 让 build 之后的产物包含 hash 后缀
|
|
28
|
+
*/
|
|
29
|
+
hash: false,
|
|
30
|
+
|
|
31
|
+
publicPath: PUBLIC_PATH,
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @name 路由配置
|
|
35
|
+
*/
|
|
36
|
+
routes,
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @name moment 的国际化配置
|
|
40
|
+
*/
|
|
41
|
+
ignoreMomentLocale: true,
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @name 快速热更新配置
|
|
45
|
+
*/
|
|
46
|
+
fastRefresh: true,
|
|
47
|
+
|
|
48
|
+
//============== 以下都是 max 的插件配置 ===============
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @name 网络请求配置
|
|
52
|
+
* @doc https://umijs.org/docs/max/request
|
|
53
|
+
*/
|
|
54
|
+
request: {},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @name 数据流插件
|
|
58
|
+
* @doc https://umijs.org/docs/max/data-flow
|
|
59
|
+
*/
|
|
60
|
+
model: {},
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @name 全局初始状态
|
|
64
|
+
*/
|
|
65
|
+
initialState: {},
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @name layout 插件
|
|
69
|
+
* @description 禁用内置 layout,子应用使用自定义布局
|
|
70
|
+
*/
|
|
71
|
+
layout: false,
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @name 其他配置
|
|
75
|
+
*/
|
|
76
|
+
esbuildMinifyIIFE: true,
|
|
77
|
+
|
|
78
|
+
define: {
|
|
79
|
+
'process.env.NODE_ENV': process.env.NODE_ENV,
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @name qiankun 微前端配置
|
|
84
|
+
* @description 作为子应用
|
|
85
|
+
* @doc https://umijs.org/docs/max/micro-frontend
|
|
86
|
+
*/
|
|
87
|
+
qiankun: {
|
|
88
|
+
slave: {},
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @name 代码拆分配置
|
|
93
|
+
* @description 确保动态 import 的模块打包为独立 chunk
|
|
94
|
+
* @doc https://umijs.org/docs/api/config#codeSplitting
|
|
95
|
+
*/
|
|
96
|
+
codeSplitting: {
|
|
97
|
+
jsStrategy: 'granularChunks',
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export default defineConfig(config);
|
|
102
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Mock API
|
|
3
|
+
* @description homepage 子应用的 Mock 数据
|
|
4
|
+
* @doc https://umijs.org/docs/guides/mock
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
// 获取用户信息
|
|
9
|
+
'GET /api/user/info': {
|
|
10
|
+
success: true,
|
|
11
|
+
data: {
|
|
12
|
+
id: 1001,
|
|
13
|
+
name: '张三',
|
|
14
|
+
email: 'zhangsan@example.com',
|
|
15
|
+
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=homepage',
|
|
16
|
+
role: 'admin',
|
|
17
|
+
department: '技术部',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
|
|
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
|
+
// 获取列表数据
|
|
34
|
+
'GET /api/items': {
|
|
35
|
+
success: true,
|
|
36
|
+
data: {
|
|
37
|
+
list: [
|
|
38
|
+
{ id: 1, title: '待审核内容 A', status: 'pending', createdAt: '2025-12-27 10:00:00' },
|
|
39
|
+
{ id: 2, title: '待审核内容 B', status: 'pending', createdAt: '2025-12-27 09:30:00' },
|
|
40
|
+
{ id: 3, title: '已通过内容 C', status: 'approved', createdAt: '2025-12-26 15:00:00' },
|
|
41
|
+
{ id: 4, title: '已拒绝内容 D', status: 'rejected', createdAt: '2025-12-26 14:00:00' },
|
|
42
|
+
],
|
|
43
|
+
total: 4,
|
|
44
|
+
page: 1,
|
|
45
|
+
pageSize: 10,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
// POST 请求示例
|
|
50
|
+
'POST /api/items/approve': (req: any, res: any) => {
|
|
51
|
+
const { id } = req.body || {};
|
|
52
|
+
res.json({
|
|
53
|
+
success: true,
|
|
54
|
+
message: `Item ${id} approved successfully`,
|
|
55
|
+
data: { id, status: 'approved' },
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= appName %>",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"author": "Easton <easton@micous.com>",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "max dev",
|
|
8
|
+
"build": "npm run build:production",
|
|
9
|
+
"build:development": "cross-env UMI_ENV=dev max build",
|
|
10
|
+
"build:production": "cross-env UMI_ENV=prod max build",
|
|
11
|
+
"build:testing": "cross-env UMI_ENV=testing max build",
|
|
12
|
+
"postinstall": "max setup",
|
|
13
|
+
"setup": "max setup",
|
|
14
|
+
"start": "npm run dev"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@audit-center/shared-styles": "workspace:*",
|
|
18
|
+
"@umijs/max": "^4.4.8",
|
|
19
|
+
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
20
|
+
"cross-env": "^10.1.0",
|
|
21
|
+
"react": "^18.2.0",
|
|
22
|
+
"react-dom": "^18.2.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@arco-design/web-react": "^2.66.6",
|
|
26
|
+
"@types/react": "^18.0.33",
|
|
27
|
+
"@types/react-dom": "^18.0.11",
|
|
28
|
+
"typescript": "^5.0.3"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name 应用入口配置
|
|
3
|
+
* @description homepage 子应用的运行时配置
|
|
4
|
+
* @doc https://umijs.org/docs/max/micro-frontend#子应用配置
|
|
5
|
+
*
|
|
6
|
+
* 注意:app.tsx 只能导出 Umi 规定的 API(qiankun、getInitialState 等)
|
|
7
|
+
* 自定义函数请放在 @/common/mainApp.ts 中
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { appLogger } from './common/logger';
|
|
11
|
+
import { type IMicroAppProps, setMainAppProps } from './common/mainApp';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @name 独立运行时加载主题
|
|
15
|
+
* @description 仅在开发环境且非 qiankun 环境中加载主题样式
|
|
16
|
+
*
|
|
17
|
+
* 实现原理:
|
|
18
|
+
* - 生产构建时 process.env.NODE_ENV !== 'development',整个 if 块被 tree-shake
|
|
19
|
+
* - 开发环境独立运行时加载主题,支持本地预览
|
|
20
|
+
* - 作为微应用运行时(无论开发还是生产),使用主应用的主题
|
|
21
|
+
*/
|
|
22
|
+
if (process.env.NODE_ENV === 'development') {
|
|
23
|
+
// 开发环境:运行时检测是否独立运行
|
|
24
|
+
if (typeof window !== 'undefined' && !window.__POWERED_BY_QIANKUN__) {
|
|
25
|
+
// 直接导入主题样式(开发环境下会被打包)
|
|
26
|
+
import('./styles/theme.less');
|
|
27
|
+
appLogger.log('Running standalone in dev mode, theme loaded');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// 生产环境:作为微应用时,主题由主应用注入,无需加载
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @name qiankun 生命周期钩子
|
|
34
|
+
* @description 子应用生命周期配置,用于与主应用通信
|
|
35
|
+
*/
|
|
36
|
+
export const qiankun = {
|
|
37
|
+
/**
|
|
38
|
+
* 在应用 bootstrap 时调用
|
|
39
|
+
*/
|
|
40
|
+
async bootstrap(props: IMicroAppProps) {
|
|
41
|
+
appLogger.log('bootstrap', props);
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
|
|
46
|
+
*/
|
|
47
|
+
async mount(props: IMicroAppProps) {
|
|
48
|
+
appLogger.log('mount', props);
|
|
49
|
+
// 保存主应用传递的 props,包括 request 实例
|
|
50
|
+
setMainAppProps(props);
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 应用每次切出/卸载会调用的方法,通常在这里我们会卸载微应用的应用实例
|
|
55
|
+
*/
|
|
56
|
+
async unmount(props: IMicroAppProps) {
|
|
57
|
+
appLogger.log('unmount', props);
|
|
58
|
+
// 清理引用
|
|
59
|
+
setMainAppProps(null);
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
|
|
64
|
+
*/
|
|
65
|
+
async update(props: IMicroAppProps) {
|
|
66
|
+
appLogger.log('update', props);
|
|
67
|
+
// 更新 props
|
|
68
|
+
setMainAppProps(props);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @name 全局初始状态
|
|
74
|
+
* @description 可以从主应用获取共享的状态
|
|
75
|
+
*/
|
|
76
|
+
export async function getInitialState() {
|
|
77
|
+
return {
|
|
78
|
+
name: '<%= appName %>',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
Binary file
|