generator-mico-cli 0.1.29 → 0.2.2-8.beta.1
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 +199 -15
- package/bin/mico.js +232 -27
- package/generators/micro-react/index.js +200 -18
- package/generators/micro-react/meta.json +13 -0
- package/generators/micro-react/templates/.commitlintrc.js +1 -0
- package/generators/micro-react/templates/.cursor/rules/always-read-docs.mdc +14 -4
- package/generators/micro-react/templates/.cursor/rules/cicd-deploy.mdc +10 -8
- package/generators/micro-react/templates/.cursor/rules/coding-conventions.mdc +1 -1
- package/generators/micro-react/templates/.cursor/rules/development-guide.mdc +3 -4
- package/generators/micro-react/templates/.cursor/rules/layout-app.mdc +38 -31
- package/generators/micro-react/templates/.cursor/rules/project-overview.mdc +7 -4
- package/generators/micro-react/templates/.cursor/rules/theme-system.mdc +10 -12
- package/generators/micro-react/templates/.eslintrc.js +25 -1
- package/generators/micro-react/templates/AGENTS.md +5 -2
- package/generators/micro-react/templates/CICD/before_build.sh +76 -0
- package/generators/micro-react/templates/CICD/start_dev.sh +27 -3
- package/generators/micro-react/templates/CICD/start_prod.sh +26 -3
- package/generators/micro-react/templates/CICD/start_test.sh +28 -3
- package/generators/micro-react/templates/CICD/wangsu_fresh_dev.sh +4 -4
- package/generators/micro-react/templates/CICD/wangsu_fresh_prod.sh +4 -4
- package/generators/micro-react/templates/CICD/wangsu_fresh_test.sh +4 -4
- package/generators/micro-react/templates/CLAUDE.md +16 -9
- package/generators/micro-react/templates/README.md +42 -4
- package/generators/micro-react/templates/_gitignore +4 -0
- package/generators/micro-react/templates/_npmrc +4 -0
- package/generators/micro-react/templates/apps/layout/config/config.dev.ts +33 -17
- package/generators/micro-react/templates/apps/layout/config/config.prod.development.ts +24 -29
- package/generators/micro-react/templates/apps/layout/config/config.prod.testing.ts +25 -6
- package/generators/micro-react/templates/apps/layout/config/config.prod.ts +16 -7
- package/generators/micro-react/templates/apps/layout/config/config.ts +27 -4
- package/generators/micro-react/templates/apps/layout/config/routes.ts +10 -5
- package/generators/micro-react/templates/apps/layout/docs/arch-/346/227/245/345/277/227/344/270/216/345/270/270/351/207/217.md +2 -2
- package/generators/micro-react/templates/apps/layout/docs/arch-/350/257/267/346/261/202/346/250/241/345/235/227.md +1 -1
- package/generators/micro-react/templates/apps/layout/docs/common-intl.md +372 -0
- package/generators/micro-react/templates/apps/layout/docs/feat-/346/236/204/345/273/272define/344/270/216/345/205/215/350/256/244/350/257/201/345/210/235/345/247/213/346/200/201.md +44 -0
- package/generators/micro-react/templates/apps/layout/docs/feature-404/351/241/265/351/235/242.md +103 -0
- package/generators/micro-react/templates/apps/layout/docs/feature-/344/270/273/351/242/230/350/211/262/345/210/207/346/215/242.md +22 -26
- 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 +185 -28
- 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 +420 -0
- package/generators/micro-react/templates/apps/layout/docs/feature-/350/267/257/347/224/261/344/270/216/350/217/234/345/215/225/350/247/243/350/200/246.md +179 -0
- package/generators/micro-react/templates/apps/layout/docs/fix-SSO/346/227/240/351/231/220/351/207/215/345/256/232/345/220/221.md +88 -0
- package/generators/micro-react/templates/apps/layout/docs/utils-timezone.md +324 -0
- package/generators/micro-react/templates/apps/layout/mock/api.mock.ts +81 -61
- package/generators/micro-react/templates/apps/layout/mock/menus.ts +114 -4
- package/generators/micro-react/templates/apps/layout/mock/pages.ts +86 -0
- package/generators/micro-react/templates/apps/layout/package.json +7 -4
- package/generators/micro-react/templates/apps/layout/src/app.tsx +122 -83
- package/generators/micro-react/templates/apps/layout/src/common/auth/index.ts +3 -0
- package/generators/micro-react/templates/apps/layout/src/common/helpers.ts +177 -0
- package/generators/micro-react/templates/apps/layout/src/common/locale.ts +22 -17
- package/generators/micro-react/templates/apps/layout/src/common/menu/parser.ts +283 -28
- package/generators/micro-react/templates/apps/layout/src/common/menu/types.ts +69 -5
- package/generators/micro-react/templates/apps/layout/src/common/micro/index.ts +34 -0
- package/generators/micro-react/templates/apps/layout/src/common/micro-prefetch.ts +109 -0
- package/generators/micro-react/templates/apps/layout/src/common/portal-data.ts +45 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/config.ts +72 -10
- package/generators/micro-react/templates/apps/layout/src/common/request/index.ts +2 -2
- package/generators/micro-react/templates/apps/layout/src/common/request/interceptors.ts +31 -3
- package/generators/micro-react/templates/apps/layout/src/common/request/sso.ts +29 -11
- package/generators/micro-react/templates/apps/layout/src/common/request/url-resolver.ts +23 -8
- package/generators/micro-react/templates/apps/layout/src/common/route-guard.ts +345 -0
- package/generators/micro-react/templates/apps/layout/src/common/theme.ts +2 -4
- package/generators/micro-react/templates/apps/layout/src/common/upload/oss.ts +3 -4
- package/generators/micro-react/templates/apps/layout/src/common/upload/types.ts +1 -1
- package/generators/micro-react/templates/apps/layout/src/common/uploadFiles.ts +1 -1
- package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.less +8 -3
- package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.tsx +25 -8
- package/generators/micro-react/templates/apps/layout/src/components/HeaderDropdown/index.tsx +20 -0
- package/generators/micro-react/templates/apps/layout/src/components/IconFont/index.tsx +5 -6
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.less +21 -6
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +83 -107
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/micro-app-manager.ts +569 -0
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/AvatarDropdown.tsx +383 -0
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/avatar-dropdown.less +35 -0
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/index.ts +2 -0
- package/generators/micro-react/templates/apps/layout/src/constants/index.ts +170 -6
- package/generators/micro-react/templates/apps/layout/src/global.less +19 -6
- package/generators/micro-react/templates/apps/layout/src/hooks/useMenu.ts +3 -2
- package/generators/micro-react/templates/apps/layout/src/hooks/useRoutePermissionRefresh.ts +72 -0
- package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.less +3 -1
- package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.tsx +10 -55
- package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +34 -4
- package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +33 -9
- package/generators/micro-react/templates/apps/layout/src/layouts/index.less +84 -13
- package/generators/micro-react/templates/apps/layout/src/layouts/index.tsx +178 -47
- package/generators/micro-react/templates/apps/layout/src/locales/en-US.ts +12 -0
- package/generators/micro-react/templates/apps/layout/src/locales/zh-CN.ts +12 -0
- package/generators/micro-react/templates/apps/layout/src/pages/403/index.tsx +34 -0
- package/generators/micro-react/templates/apps/layout/src/pages/404/index.tsx +78 -0
- package/generators/micro-react/templates/apps/layout/src/pages/Home/index.less +3 -0
- package/generators/micro-react/templates/apps/layout/src/pages/Home/index.tsx +7 -1
- package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.less +1 -1
- package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.tsx +9 -5
- package/generators/micro-react/templates/apps/layout/src/requestErrorConfig.ts +1 -1
- package/generators/micro-react/templates/apps/layout/src/services/config/index.ts +63 -0
- package/generators/micro-react/templates/apps/layout/src/services/config/type.ts +30 -0
- package/generators/micro-react/templates/apps/layout/src/services/user.ts +29 -2
- package/generators/micro-react/templates/apps/layout/tailwind.config.js +3 -0
- package/generators/micro-react/templates/deployDesc.md +3 -3
- package/generators/micro-react/templates/dev.preset.json +14 -0
- package/generators/micro-react/templates/docs/dev-preset.md +130 -0
- package/generators/micro-react/templates/package.json +21 -6
- package/generators/micro-react/templates/packages/common-intl/README.md +427 -0
- package/generators/micro-react/templates/packages/common-intl/package.json +34 -0
- package/generators/micro-react/templates/packages/common-intl/src/index.ts +7 -0
- package/generators/micro-react/templates/packages/common-intl/src/indexedDBUtils.ts +51 -0
- package/generators/micro-react/templates/packages/common-intl/src/intl.ts +50 -0
- package/generators/micro-react/templates/packages/common-intl/src/utils.ts +482 -0
- package/generators/micro-react/templates/packages/common-intl/tsconfig.json +22 -0
- package/generators/micro-react/templates/packages/common-intl/vite.config.ts +25 -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/scripts/dev-preset.js +265 -0
- package/generators/micro-react/templates/scripts/dev-preset.schema.json +39 -0
- package/generators/micro-react/templates/turbo.json +4 -1
- package/generators/subapp-react/index.js +326 -40
- package/generators/subapp-react/meta.json +10 -0
- package/generators/subapp-react/templates/homepage/.env +2 -1
- package/generators/subapp-react/templates/homepage/README.md +3 -3
- package/generators/subapp-react/templates/homepage/config/config.dev.ts +14 -7
- package/generators/subapp-react/templates/homepage/config/config.prod.development.ts +16 -5
- package/generators/subapp-react/templates/homepage/config/config.prod.testing.ts +16 -5
- package/generators/subapp-react/templates/homepage/config/config.prod.ts +14 -5
- package/generators/subapp-react/templates/homepage/config/config.ts +27 -0
- package/generators/subapp-react/templates/homepage/config/routes.ts +2 -2
- package/generators/subapp-react/templates/homepage/mock/api.mock.ts +2 -2
- package/generators/subapp-react/templates/homepage/package.json +7 -4
- package/generators/subapp-react/templates/homepage/src/app.tsx +18 -27
- package/generators/subapp-react/templates/homepage/src/common/request.ts +29 -2
- package/generators/subapp-react/templates/homepage/src/global.less +6 -5
- package/generators/subapp-react/templates/homepage/src/pages/index.less +3 -3
- package/generators/subapp-react/templates/homepage/src/pages/index.tsx +99 -60
- package/generators/subapp-react/templates/homepage/src/styles/theme.less +1 -1
- package/generators/subapp-umd/ignore-list.json +5 -0
- package/generators/subapp-umd/index.js +309 -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 +70 -0
- package/lib/utils.js +332 -2
- package/package.json +15 -2
- package/generators/micro-react/templates/apps/layout/mock/menus.json +0 -100
- package/generators/micro-react/templates/apps/layout/src/common/constants.ts +0 -38
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/container-manager.ts +0 -202
- package/generators/micro-react/templates/packages/shared-styles/README.md +0 -124
- package/generators/micro-react/templates/packages/shared-styles/arco-design-mobile-override.less +0 -91
- package/generators/micro-react/templates/packages/shared-styles/arco-override.less +0 -119
- package/generators/micro-react/templates/packages/shared-styles/index.d.ts +0 -44
- package/generators/micro-react/templates/packages/shared-styles/index.less +0 -13
- package/generators/micro-react/templates/packages/shared-styles/package.json +0 -30
- package/generators/micro-react/templates/packages/shared-styles/theme-inject.less +0 -10
- package/generators/micro-react/templates/packages/shared-styles/themes/dark/custom-var.less +0 -290
- package/generators/micro-react/templates/packages/shared-styles/themes/normal/custom-var.less +0 -269
- package/generators/micro-react/templates/packages/shared-styles/variables-only.less +0 -433
- package/generators/micro-react/templates/packages/shared-styles/variables.less +0 -452
|
@@ -9,7 +9,11 @@ const {
|
|
|
9
9
|
collectFiles,
|
|
10
10
|
transformDestPath,
|
|
11
11
|
isTemplateFile,
|
|
12
|
-
|
|
12
|
+
getPackageVersionsParallel,
|
|
13
|
+
detectPackageScope,
|
|
14
|
+
setupErrorHandlers,
|
|
15
|
+
createLogger,
|
|
16
|
+
loadMicorc,
|
|
13
17
|
} = require('../../lib/utils');
|
|
14
18
|
|
|
15
19
|
const IGNORE_LIST = require('./ignore-list.json');
|
|
@@ -20,6 +24,19 @@ setupErrorHandlers();
|
|
|
20
24
|
module.exports = class extends Generator {
|
|
21
25
|
initializing() {
|
|
22
26
|
this.monorepoRoot = process.cwd();
|
|
27
|
+
this.logger = createLogger(this);
|
|
28
|
+
|
|
29
|
+
// 检查 dry-run 模式
|
|
30
|
+
this.isDryRun = this.options.dryRun || process.env.MICO_DRY_RUN === '1';
|
|
31
|
+
|
|
32
|
+
// 加载 .micorc 配置
|
|
33
|
+
const { config: rcConfig, configPath } = loadMicorc(this.monorepoRoot);
|
|
34
|
+
this.rcConfig = rcConfig;
|
|
35
|
+
if (configPath) {
|
|
36
|
+
this.logger.verbose('Loaded config from:', configPath);
|
|
37
|
+
this.logger.verbose('Config:', JSON.stringify(rcConfig, null, 2));
|
|
38
|
+
}
|
|
39
|
+
|
|
23
40
|
const appsDir = path.join(this.monorepoRoot, 'apps');
|
|
24
41
|
const workspaceFile = path.join(this.monorepoRoot, 'pnpm-workspace.yaml');
|
|
25
42
|
|
|
@@ -45,37 +62,6 @@ module.exports = class extends Generator {
|
|
|
45
62
|
}
|
|
46
63
|
}
|
|
47
64
|
|
|
48
|
-
_detectPackageScope() {
|
|
49
|
-
// 尝试从 packages/shared-styles/package.json 读取
|
|
50
|
-
const sharedStylesPath = path.join(this.monorepoRoot, 'packages/shared-styles/package.json');
|
|
51
|
-
if (fs.existsSync(sharedStylesPath)) {
|
|
52
|
-
try {
|
|
53
|
-
const pkg = JSON.parse(fs.readFileSync(sharedStylesPath, 'utf-8'));
|
|
54
|
-
if (pkg.name && pkg.name.startsWith('@')) {
|
|
55
|
-
const match = pkg.name.match(/^(@[^/]+)\//);
|
|
56
|
-
if (match) return match[1];
|
|
57
|
-
}
|
|
58
|
-
} catch (e) {
|
|
59
|
-
// 忽略解析错误
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 尝试从根 package.json 读取
|
|
64
|
-
const rootPkgPath = path.join(this.monorepoRoot, 'package.json');
|
|
65
|
-
if (fs.existsSync(rootPkgPath)) {
|
|
66
|
-
try {
|
|
67
|
-
const pkg = JSON.parse(fs.readFileSync(rootPkgPath, 'utf-8'));
|
|
68
|
-
if (pkg.name) {
|
|
69
|
-
return `@${pkg.name}`;
|
|
70
|
-
}
|
|
71
|
-
} catch (e) {
|
|
72
|
-
// 忽略解析错误
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
65
|
async prompting() {
|
|
80
66
|
try {
|
|
81
67
|
if (!this.monorepoRoot) {
|
|
@@ -85,14 +71,15 @@ module.exports = class extends Generator {
|
|
|
85
71
|
process.exit(1);
|
|
86
72
|
}
|
|
87
73
|
|
|
88
|
-
const detectedScope = this.
|
|
74
|
+
const detectedScope = detectPackageScope(this.monorepoRoot);
|
|
75
|
+
const rc = this.rcConfig || {};
|
|
89
76
|
|
|
90
77
|
this.answers = await this.prompt([
|
|
91
78
|
{
|
|
92
79
|
type: 'input',
|
|
93
80
|
name: 'appName',
|
|
94
81
|
message: 'Sub app name',
|
|
95
|
-
default: 'subapp',
|
|
82
|
+
default: rc.defaultSubappName || 'subapp',
|
|
96
83
|
filter: (input) => toKebab(input),
|
|
97
84
|
validate: (input) => {
|
|
98
85
|
const value = toKebab(input);
|
|
@@ -108,18 +95,32 @@ module.exports = class extends Generator {
|
|
|
108
95
|
type: 'input',
|
|
109
96
|
name: 'packageScope',
|
|
110
97
|
message: 'Package scope',
|
|
111
|
-
default: detectedScope || '@my-project',
|
|
98
|
+
default: rc.packageScope || detectedScope || '@my-project',
|
|
112
99
|
validate: (input) => {
|
|
113
100
|
if (!input) return 'Package scope is required';
|
|
114
101
|
if (!input.startsWith('@')) return 'Package scope must start with @';
|
|
115
102
|
return true;
|
|
116
103
|
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
type: 'input',
|
|
107
|
+
name: 'devPort',
|
|
108
|
+
message: 'Dev server port',
|
|
109
|
+
default: rc.devPort || '8010',
|
|
110
|
+
validate: (input) => {
|
|
111
|
+
const port = Number(input);
|
|
112
|
+
if (!Number.isInteger(port) || port < 1024 || port > 65535) {
|
|
113
|
+
return 'Port must be an integer between 1024 and 65535';
|
|
114
|
+
}
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
117
|
}
|
|
118
118
|
]);
|
|
119
119
|
|
|
120
120
|
this.appName = toKebab(this.answers.appName);
|
|
121
121
|
this.appNamePascal = toPascal(this.appName);
|
|
122
122
|
this.packageScope = this.answers.packageScope;
|
|
123
|
+
this.devPort = this.answers.devPort;
|
|
123
124
|
this.templateDir = this.templatePath('homepage');
|
|
124
125
|
this.destDir = path.join(this.monorepoRoot, 'apps', this.appName);
|
|
125
126
|
} catch (error) {
|
|
@@ -131,7 +132,7 @@ module.exports = class extends Generator {
|
|
|
131
132
|
}
|
|
132
133
|
}
|
|
133
134
|
|
|
134
|
-
writing() {
|
|
135
|
+
async writing() {
|
|
135
136
|
try {
|
|
136
137
|
if (!fs.existsSync(this.templateDir)) {
|
|
137
138
|
console.error('');
|
|
@@ -141,12 +142,41 @@ module.exports = class extends Generator {
|
|
|
141
142
|
process.exit(1);
|
|
142
143
|
}
|
|
143
144
|
|
|
145
|
+
this.logger.verbose('Template directory:', this.templateDir);
|
|
146
|
+
this.logger.verbose('Destination directory:', this.destDir);
|
|
147
|
+
|
|
148
|
+
// 在 mico_cli 根目录执行 npm view,以使用该目录 .npmrc 中的 Nexus 认证
|
|
149
|
+
const cliRoot = path.resolve(__dirname, '../..');
|
|
150
|
+
this.logger.verbose('Fetching latest package versions (parallel)...');
|
|
151
|
+
|
|
152
|
+
// 并行获取版本
|
|
153
|
+
const versions = await getPackageVersionsParallel(
|
|
154
|
+
[
|
|
155
|
+
{ name: '@mico-platform/ui', fallback: '1.0.0' },
|
|
156
|
+
{ name: '@mico-platform/theme', fallback: '1.0.0' },
|
|
157
|
+
],
|
|
158
|
+
8000,
|
|
159
|
+
cliRoot,
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
const micoUiVer = versions['@mico-platform/ui'];
|
|
163
|
+
const themeVer = versions['@mico-platform/theme'];
|
|
164
|
+
|
|
165
|
+
this.logger.verbose('@mico-platform/ui version:', micoUiVer);
|
|
166
|
+
this.logger.verbose('@mico-platform/theme version:', themeVer);
|
|
167
|
+
|
|
144
168
|
const templateData = {
|
|
145
169
|
appName: this.appName,
|
|
146
170
|
AppName: this.appNamePascal,
|
|
147
|
-
packageScope: this.packageScope
|
|
171
|
+
packageScope: this.packageScope,
|
|
172
|
+
devPort: this.devPort,
|
|
173
|
+
micoUiVersion: `^${micoUiVer}`,
|
|
174
|
+
themeVersion: `^${themeVer}`,
|
|
175
|
+
micoUiVersionExact: micoUiVer
|
|
148
176
|
};
|
|
149
177
|
|
|
178
|
+
this.logger.verbose('Template data:', JSON.stringify(templateData, null, 2));
|
|
179
|
+
|
|
150
180
|
const files = collectFiles(this.templateDir, this.templateDir, IGNORE_LIST);
|
|
151
181
|
|
|
152
182
|
if (files.length === 0) {
|
|
@@ -157,17 +187,77 @@ module.exports = class extends Generator {
|
|
|
157
187
|
process.exit(1);
|
|
158
188
|
}
|
|
159
189
|
|
|
190
|
+
// Dry-run 模式:只列出文件,不实际创建
|
|
191
|
+
if (this.isDryRun) {
|
|
192
|
+
this.log('');
|
|
193
|
+
this.log('\x1b[33m📋 Dry run mode - no files will be created\x1b[0m');
|
|
194
|
+
this.log('');
|
|
195
|
+
this.log(` Sub-app: ${this.appName}`);
|
|
196
|
+
this.log(` Scope: ${this.packageScope}`);
|
|
197
|
+
this.log(` Destination: apps/${this.appName}`);
|
|
198
|
+
this.log('');
|
|
199
|
+
this.log(' Would create the following files:');
|
|
200
|
+
this.log('');
|
|
201
|
+
|
|
202
|
+
let templateCount = 0;
|
|
203
|
+
let copyCount = 0;
|
|
204
|
+
|
|
205
|
+
for (const relPath of files) {
|
|
206
|
+
const destRelPath = transformDestPath(relPath);
|
|
207
|
+
const isTemplate = isTemplateFile(relPath) || path.basename(relPath) === '.env';
|
|
208
|
+
const tag = isTemplate ? '\x1b[32m[tpl]\x1b[0m' : '\x1b[36m[cpy]\x1b[0m';
|
|
209
|
+
this.log(` ${tag} apps/${this.appName}/${destRelPath}`);
|
|
210
|
+
|
|
211
|
+
if (isTemplate) {
|
|
212
|
+
templateCount++;
|
|
213
|
+
} else {
|
|
214
|
+
copyCount++;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
this.log('');
|
|
219
|
+
this.log(` Total: ${files.length} files (${templateCount} templates, ${copyCount} static)`);
|
|
220
|
+
this.log('');
|
|
221
|
+
this.log(' Run without --dry-run to actually create these files.');
|
|
222
|
+
this.log('');
|
|
223
|
+
|
|
224
|
+
// 设置标记以跳过后续阶段
|
|
225
|
+
this._skipInstall = true;
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
this.log('');
|
|
230
|
+
this.log(`📦 Creating sub-app: ${this.appName}`);
|
|
231
|
+
this.log(` Destination: apps/${this.appName}`);
|
|
232
|
+
this.log('');
|
|
233
|
+
|
|
234
|
+
this.logger.verbose(`Processing ${files.length} files...`);
|
|
235
|
+
|
|
236
|
+
let templateCount = 0;
|
|
237
|
+
let copyCount = 0;
|
|
238
|
+
|
|
160
239
|
for (const relPath of files) {
|
|
161
240
|
const srcPath = path.join(this.templateDir, relPath);
|
|
162
241
|
const destRelPath = transformDestPath(relPath);
|
|
163
242
|
const destPath = path.join(this.destDir, destRelPath);
|
|
164
243
|
|
|
165
|
-
|
|
244
|
+
const isEnvFile = path.basename(relPath) === '.env';
|
|
245
|
+
if (isTemplateFile(relPath) || isEnvFile) {
|
|
246
|
+
this.logger.file('template', destRelPath);
|
|
166
247
|
this.fs.copyTpl(srcPath, destPath, templateData);
|
|
248
|
+
templateCount++;
|
|
167
249
|
} else {
|
|
250
|
+
this.logger.file('copy', destRelPath);
|
|
168
251
|
this.fs.copy(srcPath, destPath);
|
|
252
|
+
copyCount++;
|
|
169
253
|
}
|
|
170
254
|
}
|
|
255
|
+
|
|
256
|
+
this.logger.verbose(`Processed: ${templateCount} templates, ${copyCount} copied`);
|
|
257
|
+
|
|
258
|
+
this._updateDevPreset();
|
|
259
|
+
this._updateMockPages();
|
|
260
|
+
this._updateConfigDev();
|
|
171
261
|
} catch (error) {
|
|
172
262
|
console.error('');
|
|
173
263
|
console.error('❌ Error during file generation:');
|
|
@@ -177,12 +267,208 @@ module.exports = class extends Generator {
|
|
|
177
267
|
}
|
|
178
268
|
}
|
|
179
269
|
|
|
270
|
+
_updateDevPreset() {
|
|
271
|
+
const presetPath = path.join(this.monorepoRoot, 'dev.preset.json');
|
|
272
|
+
if (!fs.existsSync(presetPath)) {
|
|
273
|
+
this.logger.verbose('dev.preset.json not found, skipping preset update');
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
const preset = JSON.parse(fs.readFileSync(presetPath, 'utf-8'));
|
|
279
|
+
const fullApps = preset.presets?.full?.apps;
|
|
280
|
+
|
|
281
|
+
if (!Array.isArray(fullApps)) {
|
|
282
|
+
this.logger.verbose('dev.preset.json has no full.apps array, skipping');
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (fullApps.includes(this.appName)) {
|
|
287
|
+
this.logger.verbose(`"${this.appName}" already in full preset, skipping`);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
fullApps.push(this.appName);
|
|
292
|
+
fs.writeFileSync(presetPath, `${JSON.stringify(preset, null, 2)}\n`, 'utf-8');
|
|
293
|
+
|
|
294
|
+
this.log(` 📝 已将 "${this.appName}" 添加到 dev.preset.json 的 full 预设中`);
|
|
295
|
+
} catch (e) {
|
|
296
|
+
console.warn(` ⚠️ 更新 dev.preset.json 失败: ${e.message}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
_updateMockPages() {
|
|
301
|
+
const pagesPath = path.join(this.monorepoRoot, 'apps/layout/mock/pages.ts');
|
|
302
|
+
if (!fs.existsSync(pagesPath)) {
|
|
303
|
+
this.logger.verbose('apps/layout/mock/pages.ts not found, skipping');
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
try {
|
|
308
|
+
const content = fs.readFileSync(pagesPath, 'utf-8');
|
|
309
|
+
|
|
310
|
+
if (content.includes(`route: '/${this.appName}'`)) {
|
|
311
|
+
this.logger.verbose(`Route "/${this.appName}" already in mock pages, skipping`);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// 找出已有的最大 id
|
|
316
|
+
const idMatches = [...content.matchAll(/id:\s*(\d+)/g)];
|
|
317
|
+
const maxId = idMatches.reduce((max, m) => Math.max(max, Number(m[1])), 0);
|
|
318
|
+
|
|
319
|
+
const newEntry = [
|
|
320
|
+
' {',
|
|
321
|
+
` id: ${maxId + 1},`,
|
|
322
|
+
` name: '${this.appNamePascal}',`,
|
|
323
|
+
` nameEn: '${this.appNamePascal}',`,
|
|
324
|
+
` nameKey: 'page.${this.appName}',`,
|
|
325
|
+
` route: '/${this.appName}',`,
|
|
326
|
+
` base: '/${this.appName}',`,
|
|
327
|
+
` htmlUrl: '//localhost:${this.devPort}',`,
|
|
328
|
+
' jsUrls: [],',
|
|
329
|
+
' cssUrls: [],',
|
|
330
|
+
" prefixPath: '',",
|
|
331
|
+
" routeMode: 'prefix',",
|
|
332
|
+
' enabled: true,',
|
|
333
|
+
' accessControlEnabled: false,',
|
|
334
|
+
' adminOnly: false,',
|
|
335
|
+
' routeKey: null,',
|
|
336
|
+
` mainDocumentId: ${maxId + 1},`,
|
|
337
|
+
" version: '',",
|
|
338
|
+
' },',
|
|
339
|
+
].join('\n');
|
|
340
|
+
|
|
341
|
+
// 插入到兜底路由 (route: '/*') 之前
|
|
342
|
+
const lines = content.split('\n');
|
|
343
|
+
let insertIdx = -1;
|
|
344
|
+
|
|
345
|
+
for (let i = 0; i < lines.length; i++) {
|
|
346
|
+
if (lines[i].includes("route: '/*'")) {
|
|
347
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
348
|
+
if (lines[j].trim() === '{') {
|
|
349
|
+
insertIdx = j;
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (insertIdx === -1) {
|
|
358
|
+
const closingIdx = lines.findIndex((l) => l.trim() === '];');
|
|
359
|
+
if (closingIdx > 0) insertIdx = closingIdx;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (insertIdx > 0) {
|
|
363
|
+
lines.splice(insertIdx, 0, newEntry);
|
|
364
|
+
fs.writeFileSync(pagesPath, lines.join('\n'), 'utf-8');
|
|
365
|
+
this.log(` 📝 已将 "${this.appName}" 的页面配置添加到 mock/pages.ts`);
|
|
366
|
+
}
|
|
367
|
+
} catch (e) {
|
|
368
|
+
console.warn(` ⚠️ 更新 mock/pages.ts 失败: ${e.message}`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
_updateConfigDev() {
|
|
373
|
+
const configPath = path.join(this.monorepoRoot, 'apps/layout/config/config.dev.ts');
|
|
374
|
+
if (!fs.existsSync(configPath)) {
|
|
375
|
+
this.logger.verbose('apps/layout/config/config.dev.ts not found, skipping');
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
try {
|
|
380
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
381
|
+
const routeEntry = `'/${this.appName}/*'`;
|
|
382
|
+
|
|
383
|
+
if (content.includes(routeEntry)) {
|
|
384
|
+
this.logger.verbose(`Route "${routeEntry}" already in noPermissionRouteList, skipping`);
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const updated = content.replace(
|
|
389
|
+
/noPermissionRouteList:\s*\[([^\]]*)\]/,
|
|
390
|
+
(match, inner) => {
|
|
391
|
+
const trimmed = inner.trim();
|
|
392
|
+
const entries = trimmed ? `${trimmed}, ${routeEntry}` : routeEntry;
|
|
393
|
+
return `noPermissionRouteList: [${entries}]`;
|
|
394
|
+
},
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
if (updated === content) {
|
|
398
|
+
this.logger.verbose('noPermissionRouteList not found in config.dev.ts, skipping');
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
fs.writeFileSync(configPath, updated, 'utf-8');
|
|
403
|
+
this.log(` 📝 已将 "${routeEntry}" 添加到 config.dev.ts 的 noPermissionRouteList 中`);
|
|
404
|
+
} catch (e) {
|
|
405
|
+
console.warn(` ⚠️ 更新 config.dev.ts 失败: ${e.message}`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
install() {
|
|
410
|
+
// 跳过 dry-run 模式
|
|
411
|
+
if (this._skipInstall) return;
|
|
412
|
+
|
|
413
|
+
this.log('');
|
|
414
|
+
this.log('📦 正在安装依赖...');
|
|
415
|
+
try {
|
|
416
|
+
this.spawnCommandSync('pnpm', ['install'], {
|
|
417
|
+
cwd: this.monorepoRoot
|
|
418
|
+
});
|
|
419
|
+
} catch (e) {
|
|
420
|
+
this._installFailed = true;
|
|
421
|
+
this.log('');
|
|
422
|
+
this.log('⚠️ 依赖安装失败,但子应用文件已全部生成。');
|
|
423
|
+
this.logger.verbose('Install error:', e.message);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// 依赖安装成功后,格式化被修改的 layout 文件
|
|
428
|
+
const layoutDir = path.join(this.monorepoRoot, 'apps/layout');
|
|
429
|
+
if (fs.existsSync(path.join(layoutDir, '.prettierrc'))) {
|
|
430
|
+
const filesToFormat = [
|
|
431
|
+
path.join(layoutDir, 'mock/pages.ts'),
|
|
432
|
+
path.join(layoutDir, 'config/config.dev.ts'),
|
|
433
|
+
].filter((f) => fs.existsSync(f));
|
|
434
|
+
|
|
435
|
+
if (filesToFormat.length > 0) {
|
|
436
|
+
try {
|
|
437
|
+
this.spawnCommandSync(
|
|
438
|
+
'pnpm',
|
|
439
|
+
['-C', 'apps/layout', 'exec', 'prettier', '--write', ...filesToFormat],
|
|
440
|
+
{ cwd: this.monorepoRoot },
|
|
441
|
+
);
|
|
442
|
+
} catch (e) {
|
|
443
|
+
this.logger.verbose('Formatting failed (non-critical):', e.message);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
180
449
|
end() {
|
|
450
|
+
// 跳过 dry-run 模式
|
|
451
|
+
if (this._skipInstall) return;
|
|
452
|
+
|
|
453
|
+
this.log('');
|
|
454
|
+
|
|
455
|
+
if (this._installFailed) {
|
|
456
|
+
this.log('⚠️ 子应用文件已创建,但依赖安装未完成。');
|
|
457
|
+
this.log('');
|
|
458
|
+
this.log(' 请手动安装依赖:');
|
|
459
|
+
this.log('');
|
|
460
|
+
this.log(' pnpm install');
|
|
461
|
+
this.log('');
|
|
462
|
+
this.log(' 如果安装仍然失败,可尝试:');
|
|
463
|
+
this.log(' pnpm install --network-concurrency 4');
|
|
464
|
+
} else {
|
|
465
|
+
this.log('✅ 子应用创建成功!');
|
|
466
|
+
}
|
|
467
|
+
|
|
181
468
|
this.log('');
|
|
182
|
-
this.log('
|
|
469
|
+
this.log(' 后续步骤:');
|
|
183
470
|
this.log('');
|
|
184
471
|
this.log(` cd apps/${this.appName}`);
|
|
185
|
-
this.log(' pnpm install');
|
|
186
472
|
this.log(' pnpm dev');
|
|
187
473
|
this.log('');
|
|
188
474
|
}
|
|
@@ -89,12 +89,12 @@ PORT=8001
|
|
|
89
89
|
}
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
##
|
|
92
|
+
## 主题变量
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
使用 @mico-platform/theme 时,在 Less 中引入:
|
|
95
95
|
|
|
96
96
|
```less
|
|
97
|
-
@import '@
|
|
97
|
+
@import '@mico-platform/theme/variables';
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
## 相关文档
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import { defineConfig } from '@umijs/max';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* ⚠️⚠️ 不要修改这个变量名,版本升级工具会读取这个变量名,进行版本升级
|
|
7
|
+
* @name mico-ui 版本
|
|
8
|
+
* @description 开发环境使用 mico-ui 的最新版本
|
|
9
|
+
*/
|
|
10
|
+
const MICO_UI_VERSION = '<%= micoUiVersionExact %>';
|
|
11
|
+
|
|
5
12
|
/**
|
|
6
13
|
* 开发环境配置
|
|
7
14
|
* - 不配置 externals,直接打包依赖,方便独立运行调试
|
|
@@ -22,17 +29,17 @@ const config: ReturnType<typeof defineConfig> = {
|
|
|
22
29
|
// headScripts: [
|
|
23
30
|
// 'https://unpkg.com/react@18/umd/react.development.js',
|
|
24
31
|
// 'https://unpkg.com/react-dom@18/umd/react-dom.development.js',
|
|
25
|
-
// 'https://unpkg.com/@
|
|
32
|
+
// 'https://unpkg.com/@mico-platform/ui@<%= micoUiVersionExact %>/dist/arco.min.js',
|
|
26
33
|
// ],
|
|
27
34
|
|
|
28
35
|
// /**
|
|
29
36
|
// * @name 样式加载配置
|
|
30
|
-
// * @description 开发环境独立运行时加载
|
|
37
|
+
// * @description 开发环境独立运行时加载 @mico-platform/ui CSS
|
|
31
38
|
// */
|
|
32
39
|
// links: [
|
|
33
40
|
// {
|
|
34
41
|
// rel: 'stylesheet',
|
|
35
|
-
// href: 'https://unpkg.com/@
|
|
42
|
+
// href: 'https://unpkg.com/@mico-platform/ui@<%= micoUiVersionExact %>/dist/css/arco.min.css',
|
|
36
43
|
// },
|
|
37
44
|
// ],
|
|
38
45
|
|
|
@@ -43,16 +50,16 @@ const config: ReturnType<typeof defineConfig> = {
|
|
|
43
50
|
// externals: {
|
|
44
51
|
// react: 'window.React',
|
|
45
52
|
// 'react-dom': 'window.ReactDOM',
|
|
46
|
-
// '@
|
|
53
|
+
// '@mico-platform/ui': 'window.micoUI',
|
|
47
54
|
// },
|
|
48
55
|
/**
|
|
49
56
|
* @name 样式加载配置
|
|
50
|
-
* @description 开发环境独立运行时加载
|
|
57
|
+
* @description 开发环境独立运行时加载 @mico-platform/ui CSS
|
|
51
58
|
* 作为微前端子应用运行时,样式由主应用提供
|
|
52
59
|
*/
|
|
53
60
|
styles: [
|
|
54
|
-
//
|
|
55
|
-
|
|
61
|
+
// @mico-platform/ui 基础样式(使用运行时解析的最新版本号,避免 latest 标签)
|
|
62
|
+
`https://cdn-portal.micoplatform.com/portal-center/mico-ui/${MICO_UI_VERSION}/ui/dist/css/mico-ui.min.css`,
|
|
56
63
|
],
|
|
57
64
|
};
|
|
58
65
|
|
|
@@ -1,25 +1,35 @@
|
|
|
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
|
const { CDN_PUBLIC_PATH } = process.env;
|
|
5
7
|
|
|
6
8
|
const PUBLIC_PATH: string = CDN_PUBLIC_PATH
|
|
7
|
-
? `${CDN_PUBLIC_PATH.replace(/\/?$/, '/')}
|
|
8
|
-
: '
|
|
9
|
+
? `${CDN_PUBLIC_PATH.replace(/\/?$/, '/')}<%= appName %>/`
|
|
10
|
+
: '/<%= appName %>/';
|
|
9
11
|
|
|
10
12
|
const config: ReturnType<typeof defineConfig> = {
|
|
13
|
+
// 开发环境,不上传 sourcemap。调试时如有需要再解开
|
|
14
|
+
// devtool: 'hidden-source-map',
|
|
15
|
+
|
|
11
16
|
// 测试环境:将所有代码打包到一个文件
|
|
12
17
|
extraBabelPlugins: ['babel-plugin-dynamic-import-node'],
|
|
13
18
|
|
|
19
|
+
publicPath: PUBLIC_PATH,
|
|
20
|
+
cssPublicPath: PUBLIC_PATH,
|
|
21
|
+
|
|
14
22
|
// 禁用代码分割,只输出一个 JS 和一个 CSS
|
|
15
23
|
chainWebpack(memo) {
|
|
16
24
|
// 禁用 splitChunks
|
|
17
25
|
memo.optimization.splitChunks(false);
|
|
18
26
|
// 禁用 runtimeChunk
|
|
19
27
|
memo.optimization.runtimeChunk(false);
|
|
28
|
+
memo.plugins.delete('runtimePublicPath');
|
|
29
|
+
// 开发环境,不上传 sourcemap。调试时如有需要再解开
|
|
30
|
+
// applySentryPlugin({ memo, appName: '<%= appName %>' });
|
|
20
31
|
return memo;
|
|
21
32
|
},
|
|
22
|
-
publicPath: PUBLIC_PATH,
|
|
23
33
|
|
|
24
34
|
/**
|
|
25
35
|
* @name 外部依赖配置
|
|
@@ -28,12 +38,13 @@ const config: ReturnType<typeof defineConfig> = {
|
|
|
28
38
|
*
|
|
29
39
|
* 作为 qiankun 子应用时,这些库由主应用提供:
|
|
30
40
|
* - react / react-dom: 主应用已加载,避免多实例问题
|
|
31
|
-
* - @
|
|
41
|
+
* - @mico-platform/ui: 主应用已加载,复用组件和样式
|
|
32
42
|
*/
|
|
33
43
|
externals: {
|
|
34
44
|
react: 'React',
|
|
35
45
|
'react-dom': 'ReactDOM',
|
|
36
|
-
'@
|
|
46
|
+
'@mico-platform/ui': 'micoUI',
|
|
47
|
+
'@common-web/sentry': 'CommonWebSentry',
|
|
37
48
|
},
|
|
38
49
|
};
|
|
39
50
|
|
|
@@ -1,25 +1,35 @@
|
|
|
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
|
const { CDN_PUBLIC_PATH } = process.env;
|
|
5
7
|
|
|
6
8
|
const PUBLIC_PATH: string = CDN_PUBLIC_PATH
|
|
7
|
-
? `${CDN_PUBLIC_PATH.replace(/\/?$/, '/')}
|
|
8
|
-
: '
|
|
9
|
+
? `${CDN_PUBLIC_PATH.replace(/\/?$/, '/')}<%= appName %>/`
|
|
10
|
+
: '/<%= appName %>/';
|
|
9
11
|
|
|
10
12
|
const config: ReturnType<typeof defineConfig> = {
|
|
13
|
+
// 测试环境,不上传 sourcemap。调试时如有需要再解开
|
|
14
|
+
// devtool: 'hidden-source-map',
|
|
15
|
+
|
|
11
16
|
// 测试环境:将所有代码打包到一个文件
|
|
12
17
|
extraBabelPlugins: ['babel-plugin-dynamic-import-node'],
|
|
13
18
|
|
|
19
|
+
publicPath: PUBLIC_PATH,
|
|
20
|
+
cssPublicPath: PUBLIC_PATH,
|
|
21
|
+
|
|
14
22
|
// 禁用代码分割,只输出一个 JS 和一个 CSS
|
|
15
23
|
chainWebpack(memo) {
|
|
16
24
|
// 禁用 splitChunks
|
|
17
25
|
memo.optimization.splitChunks(false);
|
|
18
26
|
// 禁用 runtimeChunk
|
|
19
27
|
memo.optimization.runtimeChunk(false);
|
|
28
|
+
memo.plugins.delete('runtimePublicPath');
|
|
29
|
+
// 测试环境,不上传 sourcemap。调试时如有需要再解开
|
|
30
|
+
// applySentryPlugin({ memo, appName: '<%= appName %>' });
|
|
20
31
|
return memo;
|
|
21
32
|
},
|
|
22
|
-
publicPath: PUBLIC_PATH,
|
|
23
33
|
|
|
24
34
|
/**
|
|
25
35
|
* @name 外部依赖配置
|
|
@@ -28,12 +38,13 @@ const config: ReturnType<typeof defineConfig> = {
|
|
|
28
38
|
*
|
|
29
39
|
* 作为 qiankun 子应用时,这些库由主应用提供:
|
|
30
40
|
* - react / react-dom: 主应用已加载,避免多实例问题
|
|
31
|
-
* - @
|
|
41
|
+
* - @mico-platform/ui: 主应用已加载,复用组件和样式
|
|
32
42
|
*/
|
|
33
43
|
externals: {
|
|
34
44
|
react: 'React',
|
|
35
45
|
'react-dom': 'ReactDOM',
|
|
36
|
-
'@
|
|
46
|
+
'@mico-platform/ui': 'micoUI',
|
|
47
|
+
'@common-web/sentry': 'CommonWebSentry',
|
|
37
48
|
},
|
|
38
49
|
};
|
|
39
50
|
|