generator-mico-cli 0.2.1 → 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 +32 -16
- 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 +5 -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/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 +308 -63
- 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 +111 -76
- 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 +192 -42
- 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 +1 -1
- 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 -149
- 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 +18 -9
- 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 +24 -8
- package/generators/micro-react/templates/apps/layout/src/layouts/index.less +84 -13
- package/generators/micro-react/templates/apps/layout/src/layouts/index.tsx +156 -69
- 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 +8 -2
- 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 +3 -3
- 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 +21 -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,10 @@ const {
|
|
|
9
9
|
collectFiles,
|
|
10
10
|
transformDestPath,
|
|
11
11
|
isTemplateFile,
|
|
12
|
-
|
|
12
|
+
getPackageVersionsParallel,
|
|
13
|
+
setupErrorHandlers,
|
|
14
|
+
createLogger,
|
|
15
|
+
loadMicorc,
|
|
13
16
|
} = require('../../lib/utils');
|
|
14
17
|
|
|
15
18
|
const IGNORE_LIST = require('./ignore-list.json');
|
|
@@ -20,61 +23,98 @@ setupErrorHandlers();
|
|
|
20
23
|
module.exports = class extends Generator {
|
|
21
24
|
initializing() {
|
|
22
25
|
this.projectRoot = process.cwd();
|
|
26
|
+
this.logger = createLogger(this);
|
|
23
27
|
|
|
24
|
-
//
|
|
28
|
+
// 检查 dry-run 模式
|
|
29
|
+
this.isDryRun = this.options.dryRun || process.env.MICO_DRY_RUN === '1';
|
|
30
|
+
|
|
31
|
+
// 加载 .micorc 配置
|
|
32
|
+
const { config: rcConfig, configPath } = loadMicorc(this.projectRoot);
|
|
33
|
+
this.rcConfig = rcConfig;
|
|
34
|
+
if (configPath) {
|
|
35
|
+
this.logger.verbose('Loaded config from:', configPath);
|
|
36
|
+
this.logger.verbose('Config:', JSON.stringify(rcConfig, null, 2));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 检查当前目录是否已是一个 monorepo(--force 跳过此检查)
|
|
25
40
|
const workspaceFile = path.join(this.projectRoot, 'pnpm-workspace.yaml');
|
|
26
|
-
if (fs.existsSync(workspaceFile)) {
|
|
41
|
+
if (fs.existsSync(workspaceFile) && !this.options.force) {
|
|
27
42
|
console.error('');
|
|
28
43
|
console.error('❌ Error: Current directory is already a monorepo.');
|
|
29
44
|
console.error('');
|
|
30
45
|
console.error(' A pnpm-workspace.yaml file already exists.');
|
|
31
|
-
console.error(
|
|
46
|
+
console.error(
|
|
47
|
+
' Please run this command in an empty directory or specify a new project name.',
|
|
48
|
+
);
|
|
32
49
|
console.error('');
|
|
33
50
|
console.error(' Usage:');
|
|
34
51
|
console.error(' mkdir my-project && cd my-project');
|
|
35
52
|
console.error(' mico create micro-react');
|
|
36
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('');
|
|
37
57
|
process.exit(1);
|
|
38
58
|
}
|
|
39
59
|
}
|
|
40
60
|
|
|
41
61
|
async prompting() {
|
|
42
62
|
try {
|
|
63
|
+
// 使用 .micorc 中的值作为默认值
|
|
64
|
+
const rc = this.rcConfig || {};
|
|
65
|
+
|
|
43
66
|
this.answers = await this.prompt([
|
|
44
67
|
{
|
|
45
68
|
type: 'input',
|
|
46
69
|
name: 'projectName',
|
|
47
70
|
message: 'Project name',
|
|
48
|
-
default: path.basename(this.projectRoot),
|
|
71
|
+
default: rc.projectName || path.basename(this.projectRoot),
|
|
49
72
|
filter: (input) => toKebab(input),
|
|
50
73
|
validate: (input) => {
|
|
51
74
|
const value = toKebab(input);
|
|
52
75
|
if (!value) return 'Project name is required';
|
|
53
76
|
return true;
|
|
54
|
-
}
|
|
77
|
+
},
|
|
55
78
|
},
|
|
56
79
|
{
|
|
57
80
|
type: 'input',
|
|
58
81
|
name: 'packageScope',
|
|
59
82
|
message: 'Package scope (e.g., @my-project)',
|
|
60
|
-
default: (answers) => `@${toKebab(answers.projectName)}`,
|
|
83
|
+
default: (answers) => rc.packageScope || `@${toKebab(answers.projectName)}`,
|
|
61
84
|
validate: (input) => {
|
|
62
85
|
if (!input) return 'Package scope is required';
|
|
63
|
-
if (!input.startsWith('@'))
|
|
86
|
+
if (!input.startsWith('@'))
|
|
87
|
+
return 'Package scope must start with @';
|
|
64
88
|
return true;
|
|
65
|
-
}
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
type: 'input',
|
|
93
|
+
name: 'cdnPrefix',
|
|
94
|
+
message: `CDN path prefix (用于区分不同业务线的 CDN 目录)
|
|
95
|
+
示例:CDN 完整路径 = https://cdn.example.com/<prefix>/<projectName>/<version>/
|
|
96
|
+
- 留空: https://cdn.example.com/my-project/1.0.0/
|
|
97
|
+
- 输入 "portal": https://cdn.example.com/portal/my-project/1.0.0/
|
|
98
|
+
- 输入 "admin/v2": https://cdn.example.com/admin/v2/my-project/1.0.0/
|
|
99
|
+
Prefix`,
|
|
100
|
+
default: rc.cdnPrefix || '',
|
|
101
|
+
filter: (input) => {
|
|
102
|
+
// 移除首尾斜杠,规范化路径
|
|
103
|
+
return input.trim().replace(/^\/+|\/+$/g, '');
|
|
104
|
+
},
|
|
66
105
|
},
|
|
67
106
|
{
|
|
68
107
|
type: 'input',
|
|
69
108
|
name: 'author',
|
|
70
109
|
message: 'Author',
|
|
71
|
-
default: 'Your Name <email@example.com>'
|
|
72
|
-
}
|
|
110
|
+
default: rc.author || 'Your Name <email@example.com>',
|
|
111
|
+
},
|
|
73
112
|
]);
|
|
74
113
|
|
|
75
114
|
this.projectName = toKebab(this.answers.projectName);
|
|
76
115
|
this.ProjectName = toPascal(this.projectName);
|
|
77
116
|
this.packageScope = this.answers.packageScope;
|
|
117
|
+
this.cdnPrefix = this.answers.cdnPrefix;
|
|
78
118
|
this.author = this.answers.author;
|
|
79
119
|
this.templateDir = this.templatePath();
|
|
80
120
|
this.destDir = this.projectRoot;
|
|
@@ -87,7 +127,7 @@ module.exports = class extends Generator {
|
|
|
87
127
|
}
|
|
88
128
|
}
|
|
89
129
|
|
|
90
|
-
writing() {
|
|
130
|
+
async writing() {
|
|
91
131
|
try {
|
|
92
132
|
if (!fs.existsSync(this.templateDir)) {
|
|
93
133
|
console.error('');
|
|
@@ -97,14 +137,50 @@ module.exports = class extends Generator {
|
|
|
97
137
|
process.exit(1);
|
|
98
138
|
}
|
|
99
139
|
|
|
140
|
+
this.logger.verbose('Template directory:', this.templateDir);
|
|
141
|
+
this.logger.verbose('Destination directory:', this.destDir);
|
|
142
|
+
|
|
143
|
+
// 在 mico_cli 根目录执行 npm view,以使用该目录 .npmrc 中的 Nexus 认证
|
|
144
|
+
const cliRoot = path.resolve(__dirname, '../..');
|
|
145
|
+
this.logger.verbose('Fetching latest package versions (parallel)...');
|
|
146
|
+
|
|
147
|
+
// 并行获取版本
|
|
148
|
+
const versions = await getPackageVersionsParallel(
|
|
149
|
+
[
|
|
150
|
+
{ name: '@mico-platform/ui', fallback: '1.0.0' },
|
|
151
|
+
{ name: '@mico-platform/theme', fallback: '1.0.0' },
|
|
152
|
+
],
|
|
153
|
+
8000,
|
|
154
|
+
cliRoot,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const micoUiVer = versions['@mico-platform/ui'];
|
|
158
|
+
const themeVer = versions['@mico-platform/theme'];
|
|
159
|
+
|
|
160
|
+
this.logger.verbose('@mico-platform/ui version:', micoUiVer);
|
|
161
|
+
this.logger.verbose('@mico-platform/theme version:', themeVer);
|
|
162
|
+
|
|
163
|
+
// 构建 CDN 路径片段:如果有 prefix 则加上斜杠前缀,否则为空
|
|
164
|
+
const cdnPrefixPath = this.cdnPrefix ? `${this.cdnPrefix}/` : '';
|
|
165
|
+
|
|
100
166
|
const templateData = {
|
|
101
167
|
projectName: this.projectName,
|
|
102
168
|
ProjectName: this.ProjectName,
|
|
103
169
|
packageScope: this.packageScope,
|
|
104
|
-
author: this.author
|
|
170
|
+
author: this.author,
|
|
171
|
+
micoUiVersion: `^${micoUiVer}`,
|
|
172
|
+
themeVersion: `^${themeVer}`,
|
|
173
|
+
cdnPrefix: this.cdnPrefix,
|
|
174
|
+
cdnPrefixPath, // 用于拼接路径,已包含尾部斜杠
|
|
105
175
|
};
|
|
106
176
|
|
|
107
|
-
|
|
177
|
+
this.logger.verbose('Template data:', JSON.stringify(templateData, null, 2));
|
|
178
|
+
|
|
179
|
+
const files = collectFiles(
|
|
180
|
+
this.templateDir,
|
|
181
|
+
this.templateDir,
|
|
182
|
+
IGNORE_LIST,
|
|
183
|
+
);
|
|
108
184
|
|
|
109
185
|
if (files.length === 0) {
|
|
110
186
|
console.error('');
|
|
@@ -114,22 +190,72 @@ module.exports = class extends Generator {
|
|
|
114
190
|
process.exit(1);
|
|
115
191
|
}
|
|
116
192
|
|
|
193
|
+
// Dry-run 模式:只列出文件,不实际创建
|
|
194
|
+
if (this.isDryRun) {
|
|
195
|
+
this.log('');
|
|
196
|
+
this.log('\x1b[33m📋 Dry run mode - no files will be created\x1b[0m');
|
|
197
|
+
this.log('');
|
|
198
|
+
this.log(` Project: ${this.projectName}`);
|
|
199
|
+
this.log(` Scope: ${this.packageScope}`);
|
|
200
|
+
this.log(` Destination: ${this.destDir}`);
|
|
201
|
+
this.log('');
|
|
202
|
+
this.log(' Would create the following files:');
|
|
203
|
+
this.log('');
|
|
204
|
+
|
|
205
|
+
let templateCount = 0;
|
|
206
|
+
let copyCount = 0;
|
|
207
|
+
|
|
208
|
+
for (const relPath of files) {
|
|
209
|
+
const destRelPath = transformDestPath(relPath);
|
|
210
|
+
const isTemplate = isTemplateFile(relPath);
|
|
211
|
+
const tag = isTemplate ? '\x1b[32m[tpl]\x1b[0m' : '\x1b[36m[cpy]\x1b[0m';
|
|
212
|
+
this.log(` ${tag} ${destRelPath}`);
|
|
213
|
+
|
|
214
|
+
if (isTemplate) {
|
|
215
|
+
templateCount++;
|
|
216
|
+
} else {
|
|
217
|
+
copyCount++;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
this.log('');
|
|
222
|
+
this.log(` Total: ${files.length} files (${templateCount} templates, ${copyCount} static)`);
|
|
223
|
+
this.log('');
|
|
224
|
+
this.log(' Run without --dry-run to actually create these files.');
|
|
225
|
+
this.log('');
|
|
226
|
+
|
|
227
|
+
// 设置标记以跳过后续阶段
|
|
228
|
+
this._skipInstall = true;
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
117
232
|
this.log('');
|
|
118
233
|
this.log(`📦 Creating project: ${this.projectName}`);
|
|
119
234
|
this.log(` Scope: ${this.packageScope}`);
|
|
120
235
|
this.log('');
|
|
121
236
|
|
|
237
|
+
this.logger.verbose(`Processing ${files.length} files...`);
|
|
238
|
+
|
|
239
|
+
let templateCount = 0;
|
|
240
|
+
let copyCount = 0;
|
|
241
|
+
|
|
122
242
|
for (const relPath of files) {
|
|
123
243
|
const srcPath = path.join(this.templateDir, relPath);
|
|
124
244
|
const destRelPath = transformDestPath(relPath);
|
|
125
245
|
const destPath = path.join(this.destDir, destRelPath);
|
|
126
246
|
|
|
127
247
|
if (isTemplateFile(relPath)) {
|
|
248
|
+
this.logger.file('template', destRelPath);
|
|
128
249
|
this.fs.copyTpl(srcPath, destPath, templateData);
|
|
250
|
+
templateCount++;
|
|
129
251
|
} else {
|
|
252
|
+
this.logger.file('copy', destRelPath);
|
|
130
253
|
this.fs.copy(srcPath, destPath);
|
|
254
|
+
copyCount++;
|
|
131
255
|
}
|
|
132
256
|
}
|
|
257
|
+
|
|
258
|
+
this.logger.verbose(`Processed: ${templateCount} templates, ${copyCount} copied`);
|
|
133
259
|
} catch (error) {
|
|
134
260
|
console.error('');
|
|
135
261
|
console.error('❌ Error during file generation:');
|
|
@@ -139,15 +265,71 @@ module.exports = class extends Generator {
|
|
|
139
265
|
}
|
|
140
266
|
}
|
|
141
267
|
|
|
268
|
+
install() {
|
|
269
|
+
// 跳过 dry-run 模式
|
|
270
|
+
if (this._skipInstall) return;
|
|
271
|
+
|
|
272
|
+
// 检查并初始化 git
|
|
273
|
+
const gitDir = path.join(this.destDir, '.git');
|
|
274
|
+
if (!fs.existsSync(gitDir)) {
|
|
275
|
+
this.log('');
|
|
276
|
+
this.log('🔧 初始化 Git 仓库...');
|
|
277
|
+
this.spawnCommandSync('git', ['init'], {
|
|
278
|
+
cwd: this.destDir,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
this.log('');
|
|
283
|
+
this.log('📦 正在安装依赖...');
|
|
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
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
142
311
|
end() {
|
|
312
|
+
// 跳过 dry-run 模式
|
|
313
|
+
if (this._skipInstall) return;
|
|
314
|
+
|
|
143
315
|
this.log('');
|
|
144
|
-
|
|
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
|
+
|
|
145
330
|
this.log('');
|
|
146
331
|
this.log(' 后续步骤:');
|
|
147
332
|
this.log('');
|
|
148
|
-
this.log(' # 安装依赖');
|
|
149
|
-
this.log(' pnpm install');
|
|
150
|
-
this.log('');
|
|
151
333
|
this.log(' # 启动开发服务器');
|
|
152
334
|
this.log(' pnpm dev');
|
|
153
335
|
this.log('');
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "micro-react",
|
|
3
|
+
"description": "创建基于 qiankun 的微前端 Monorepo 项目",
|
|
4
|
+
"usage": "mkdir my-project && cd my-project && mico create micro-react",
|
|
5
|
+
"features": [
|
|
6
|
+
"Turborepo + pnpm Workspace",
|
|
7
|
+
"qiankun 微前端架构",
|
|
8
|
+
"Arco Design + Tailwind CSS",
|
|
9
|
+
"主题切换、国际化、认证模块",
|
|
10
|
+
"可配置 CDN 路径前缀(支持多业务线隔离)",
|
|
11
|
+
"Sentry 错误监控与 SourceMap 上传"
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -20,8 +20,15 @@ docs/
|
|
|
20
20
|
### 2. Layout 应用文档 (`/apps/layout/docs/`)
|
|
21
21
|
```
|
|
22
22
|
apps/layout/docs/
|
|
23
|
-
├── feature-微前端模式.md
|
|
24
|
-
|
|
23
|
+
├── feature-微前端模式.md # qiankun 微前端架构
|
|
24
|
+
├── feature-路由与菜单解耦.md # PAGES/MENUS 数据源分离、双层权限
|
|
25
|
+
├── feature-菜单权限控制.md # sideMenus 白名单、认证与授权分离
|
|
26
|
+
├── feature-主题色切换.md # 主题系统实现
|
|
27
|
+
├── feature-404页面.md # 404 页面
|
|
28
|
+
├── arch-请求模块.md # HTTP 请求层模块化设计
|
|
29
|
+
├── arch-日志与常量.md # Logger 工具与常量管理
|
|
30
|
+
├── common-intl.md # 国际化公共包
|
|
31
|
+
└── utils-timezone.md # 时区工具
|
|
25
32
|
```
|
|
26
33
|
|
|
27
34
|
### 3. 其他应用文档
|
|
@@ -33,8 +40,9 @@ apps/layout/docs/
|
|
|
33
40
|
|
|
34
41
|
### Step 1: 确认需求涉及的模块
|
|
35
42
|
- 微前端相关 → 阅读 `apps/layout/docs/feature-微前端模式.md`
|
|
43
|
+
- 路由/菜单/权限相关 → 阅读 `apps/layout/docs/feature-路由与菜单解耦.md` 和 `apps/layout/docs/feature-菜单权限控制.md`
|
|
36
44
|
- 主题/样式相关 → 阅读 `apps/layout/docs/feature-主题色切换.md`
|
|
37
|
-
- 请求/认证相关 → 阅读 `
|
|
45
|
+
- 请求/认证相关 → 阅读 `apps/layout/docs/arch-请求模块.md` 和 `src/common/auth/` 源码
|
|
38
46
|
- 菜单相关 → 阅读 `src/common/menu/` 源码
|
|
39
47
|
|
|
40
48
|
### Step 2: 查找相关文档
|
|
@@ -54,9 +62,11 @@ find . -name "*.md" -type f | grep -v node_modules
|
|
|
54
62
|
| 需求类型 | 必读文档 |
|
|
55
63
|
|---------|---------|
|
|
56
64
|
| 新建子应用 | `apps/layout/docs/feature-微前端模式.md` |
|
|
65
|
+
| 路由/页面配置 | `apps/layout/docs/feature-路由与菜单解耦.md` |
|
|
66
|
+
| 权限控制 | `apps/layout/docs/feature-菜单权限控制.md` |
|
|
57
67
|
| 主题适配 | `apps/layout/docs/feature-主题色切换.md` |
|
|
58
68
|
| 提交代码 | `docs/commit-message.md` |
|
|
59
|
-
| API 请求 | `
|
|
69
|
+
| API 请求 | `apps/layout/docs/arch-请求模块.md` |
|
|
60
70
|
| 认证登录 | `src/common/auth/` 目录源码 |
|
|
61
71
|
| 菜单配置 | `src/common/menu/types.ts` 类型定义 |
|
|
62
72
|
|
|
@@ -21,7 +21,7 @@ globs: ["CICD/**", "deployDesc.md"]
|
|
|
21
21
|
│ ↓ │
|
|
22
22
|
│ ┌─────────────────────────────────────────────────────────────┐│
|
|
23
23
|
│ │ 构建产物:dist/{app}/ ││
|
|
24
|
-
│ │ 上传 CDN:cdn-portal[-env].micoplatform.com/<%= projectName %>/ ││
|
|
24
|
+
│ │ 上传 CDN:cdn-portal[-env].micoplatform.com/<%= cdnPrefixPath %><%= projectName %>/ ││
|
|
25
25
|
│ └─────────────────────────────────────────────────────────────┘│
|
|
26
26
|
└─────────────────────────────────────────────────────────────────┘
|
|
27
27
|
```
|
|
@@ -51,7 +51,7 @@ pnpm install
|
|
|
51
51
|
VERSION=$(node -p "require('./package.json').version")
|
|
52
52
|
|
|
53
53
|
# 3. 设置 CDN 路径
|
|
54
|
-
export CDN_PUBLIC_PATH="https://cdn-portal[-env].micoplatform.com/<%= projectName %>/${VERSION}/"
|
|
54
|
+
export CDN_PUBLIC_PATH="https://cdn-portal[-env].micoplatform.com/<%= cdnPrefixPath %><%= projectName %>/${VERSION}/"
|
|
55
55
|
|
|
56
56
|
# 4. 执行构建
|
|
57
57
|
pnpm run build:[environment]
|
|
@@ -78,12 +78,14 @@ echo "VERSION=$VERSION" > .env_x_<%= projectName %>
|
|
|
78
78
|
### CDN 路径结构
|
|
79
79
|
```
|
|
80
80
|
cdn-portal.micoplatform.com/
|
|
81
|
-
|
|
82
|
-
└──
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
<% if (cdnPrefix) { %>└── <%= cdnPrefix %>/
|
|
82
|
+
└── <%= projectName %>/
|
|
83
|
+
<% } else { %>└── <%= projectName %>/
|
|
84
|
+
<% } %> └── {version}/
|
|
85
|
+
└── dist/
|
|
86
|
+
├── layout/ # 主应用
|
|
87
|
+
├── homepage/ # 子应用
|
|
88
|
+
└── ...
|
|
87
89
|
```
|
|
88
90
|
|
|
89
91
|
## 环境变量
|
|
@@ -168,7 +168,7 @@ import React, { useState, useEffect } from 'react';
|
|
|
168
168
|
import { useLocation } from '@umijs/max';
|
|
169
169
|
|
|
170
170
|
// 2. 第三方库
|
|
171
|
-
import { Button, Modal } from '@
|
|
171
|
+
import { Button, Modal } from '@mico-platform/ui';
|
|
172
172
|
import dayjs from 'dayjs';
|
|
173
173
|
|
|
174
174
|
// 3. 项目内部模块(使用 @ 别名)
|
|
@@ -179,8 +179,7 @@ document.body.setAttribute('data-theme', 'dark');
|
|
|
179
179
|
### 文件位置
|
|
180
180
|
```
|
|
181
181
|
apps/layout/mock/
|
|
182
|
-
├── menus.
|
|
183
|
-
├── menus.ts # 菜单数据处理
|
|
182
|
+
├── menus.ts # 菜单 Mock 数据(带类型)
|
|
184
183
|
└── user.mock.ts # 用户相关 Mock API
|
|
185
184
|
```
|
|
186
185
|
|
|
@@ -274,7 +273,7 @@ sh CICD/start_prod.sh
|
|
|
274
273
|
|
|
275
274
|
构建产物上传到 CDN:
|
|
276
275
|
```
|
|
277
|
-
cdn-portal[-env].micoplatform.com/<%= projectName %>/{version}/dist/{app}/
|
|
276
|
+
cdn-portal[-env].micoplatform.com/<%= cdnPrefixPath %><%= projectName %>/{version}/dist/{app}/
|
|
278
277
|
```
|
|
279
278
|
|
|
280
279
|
- `version`:`package.json` 的 version 字段
|
|
@@ -290,6 +289,6 @@ cdn-portal[-env].micoplatform.com/<%= projectName %>/{version}/dist/{app}/
|
|
|
290
289
|
## 相关链接
|
|
291
290
|
|
|
292
291
|
- [UmiJS 文档](https://umijs.org/)
|
|
293
|
-
- [
|
|
292
|
+
- [@mico-platform/ui](hhttps://mico-ui.micoportal-test.com/react/docs/start)
|
|
294
293
|
- [qiankun 文档](https://qiankun.umijs.org/)
|
|
295
294
|
- [Turborepo 文档](https://turbo.build/repo)
|
|
@@ -52,10 +52,7 @@ apps/layout/
|
|
|
52
52
|
├── services/ # API 服务
|
|
53
53
|
├── models/ # Umi Model
|
|
54
54
|
├── locales/ # 国际化
|
|
55
|
-
└── styles/ #
|
|
56
|
-
├── themes/ # 主题变量
|
|
57
|
-
├── variables.less # Less 变量
|
|
58
|
-
└── arco-override.less # Arco 覆盖
|
|
55
|
+
└── styles/ # 主题样式(变量来自 @mico-platform/theme)
|
|
59
56
|
```
|
|
60
57
|
|
|
61
58
|
## 核心模块
|
|
@@ -66,24 +63,27 @@ apps/layout/
|
|
|
66
63
|
const BasicLayout: React.FC = () => {
|
|
67
64
|
const location = useLocation();
|
|
68
65
|
|
|
69
|
-
//
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
return extractRoutes(menus);
|
|
66
|
+
// 所有页面路由(优先 PAGES,降级 MENUS)— 用于路由匹配和渲染
|
|
67
|
+
const allPageRoutes = useMemo(() => {
|
|
68
|
+
return getDynamicRoutes();
|
|
73
69
|
}, []);
|
|
74
70
|
|
|
75
|
-
//
|
|
71
|
+
// 菜单路由(从 MENUS)— 用于权限交叉引用
|
|
72
|
+
const allMenuRoutes = useMemo(() => {
|
|
73
|
+
return extractRoutes(getMenus());
|
|
74
|
+
}, []);
|
|
75
|
+
|
|
76
|
+
// 当前路由配置(从所有页面路由中查找)
|
|
76
77
|
const currentRoute = useMemo(() => {
|
|
77
|
-
return findRouteByPath(
|
|
78
|
-
}, [
|
|
78
|
+
return findRouteByPath(allPageRoutes, location.pathname);
|
|
79
|
+
}, [allPageRoutes, location.pathname]);
|
|
79
80
|
|
|
80
81
|
// 渲染页面内容
|
|
81
82
|
const renderContent = () => {
|
|
82
|
-
// 微应用类型使用 MicroAppLoader
|
|
83
83
|
if (currentRoute?.loadType === 'microapp' && currentRoute.entry) {
|
|
84
|
-
|
|
84
|
+
const appName = getAppNameFromEntry(currentRoute.entry);
|
|
85
|
+
return <MicroAppLoader entry={currentRoute.entry} name={appName} />;
|
|
85
86
|
}
|
|
86
|
-
// 内部路由使用 Outlet
|
|
87
87
|
return <Outlet />;
|
|
88
88
|
};
|
|
89
89
|
|
|
@@ -101,28 +101,36 @@ const BasicLayout: React.FC = () => {
|
|
|
101
101
|
};
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
### 2. 菜单系统 (common/menu/)
|
|
104
|
+
### 2. 全局数据源 (common/portal-data.ts) + 菜单系统 (common/menu/)
|
|
105
105
|
|
|
106
106
|
```typescript
|
|
107
|
-
//
|
|
108
|
-
const
|
|
107
|
+
// 获取页面列表 (window.__MICO_PAGES__)
|
|
108
|
+
const pages = getPages();
|
|
109
|
+
|
|
110
|
+
// 获取菜单树 (window.__MICO_MENUS__)
|
|
111
|
+
const menus = getMenus();
|
|
109
112
|
|
|
110
|
-
//
|
|
111
|
-
const routes =
|
|
113
|
+
// 从页面列表提取动态路由(优先数据源)
|
|
114
|
+
const routes = getDynamicRoutes();
|
|
112
115
|
|
|
113
|
-
//
|
|
116
|
+
// 从菜单树提取路由(用于权限交叉引用)
|
|
117
|
+
const menuRoutes = extractRoutes(menus);
|
|
118
|
+
|
|
119
|
+
// 解析菜单项(用于侧边栏渲染)
|
|
114
120
|
const menuItems = parseMenuItems(menus);
|
|
115
121
|
|
|
116
122
|
// 查找当前路由
|
|
117
123
|
const currentRoute = findRouteByPath(routes, pathname);
|
|
124
|
+
|
|
125
|
+
// 通过 pageId 查找页面(O(1))
|
|
126
|
+
const page = getPageById(pageId);
|
|
118
127
|
```
|
|
119
128
|
|
|
120
129
|
### 3. 动态路由 (app.tsx)
|
|
121
130
|
|
|
122
131
|
```typescript
|
|
123
132
|
export function patchClientRoutes({ routes }: { routes: any[] }) {
|
|
124
|
-
const
|
|
125
|
-
const dynamicRoutes = extractRoutes(menus);
|
|
133
|
+
const dynamicRoutes = getDynamicRoutes(); // 从 __MICO_PAGES__ 获取
|
|
126
134
|
|
|
127
135
|
const rootRoute = routes.find((r) => r.path === '/');
|
|
128
136
|
dynamicRoutes.forEach((route) => {
|
|
@@ -131,9 +139,7 @@ export function patchClientRoutes({ routes }: { routes: any[] }) {
|
|
|
131
139
|
name: route.name,
|
|
132
140
|
meta: {
|
|
133
141
|
loadType: route.loadType,
|
|
134
|
-
|
|
135
|
-
jsUrls: route.jsUrls,
|
|
136
|
-
cssUrls: route.cssUrls,
|
|
142
|
+
entry: route.entry,
|
|
137
143
|
},
|
|
138
144
|
});
|
|
139
145
|
});
|
|
@@ -206,7 +212,7 @@ const { isAuthenticated, user, logout } = useAuth();
|
|
|
206
212
|
### 主题变量引入
|
|
207
213
|
```less
|
|
208
214
|
// 在组件样式中使用
|
|
209
|
-
@import '
|
|
215
|
+
@import '@mico-platform/theme/variables';
|
|
210
216
|
|
|
211
217
|
.my-component {
|
|
212
218
|
background: @color-fill-1;
|
|
@@ -268,8 +274,9 @@ const { collapsed } = useModel('global');
|
|
|
268
274
|
|
|
269
275
|
## 注意事项
|
|
270
276
|
|
|
271
|
-
1.
|
|
272
|
-
2. **路由动态生成**: 在 `patchClientRoutes`
|
|
273
|
-
3.
|
|
274
|
-
4.
|
|
275
|
-
5.
|
|
277
|
+
1. **数据来源**: 页面列表通过 `window.__MICO_PAGES__` 注入,菜单树通过 `window.__MICO_MENUS__` 注入
|
|
278
|
+
2. **路由动态生成**: 在 `patchClientRoutes` 中优先从 `__MICO_PAGES__` 生成路由
|
|
279
|
+
3. **权限交叉引用**: 菜单路由(`__MICO_MENUS__`)用于权限判断,页面路由(`__MICO_PAGES__`)用于渲染
|
|
280
|
+
4. **微应用判断**: 根据 `htmlUrl` 或 `jsUrls` 判断是否为微应用
|
|
281
|
+
5. **主题初始化**: 在 `app.tsx` 中调用 `initTheme()` 避免闪烁
|
|
282
|
+
6. **认证共享**: 子应用使用主应用传递的 `request` 实例
|
|
@@ -16,7 +16,7 @@ alwaysApply: true
|
|
|
16
16
|
| **Monorepo** | Turborepo + pnpm Workspace |
|
|
17
17
|
| **前端框架** | UmiJS 4 (@umijs/max)、React 18、TypeScript |
|
|
18
18
|
| **微前端** | qiankun |
|
|
19
|
-
| **UI 组件** |
|
|
19
|
+
| **UI 组件** | @mico-platform/ui |
|
|
20
20
|
| **样式方案** | Tailwind CSS + Less + CSS Variables |
|
|
21
21
|
| **代码规范** | ESLint、Stylelint、Husky、Commitlint |
|
|
22
22
|
|
|
@@ -61,20 +61,21 @@ alwaysApply: true
|
|
|
61
61
|
- **关键文件**:
|
|
62
62
|
- `src/layouts/index.tsx` - 主布局组件
|
|
63
63
|
- `src/components/MicroAppLoader/` - 微应用加载器
|
|
64
|
-
- `src/common/menu/parser.ts` -
|
|
64
|
+
- `src/common/menu/parser.ts` - 菜单解析、页面数据提取与路由生成
|
|
65
65
|
- `src/common/request/index.ts` - 统一请求封装
|
|
66
66
|
- `src/hooks/useTheme.ts` - 主题管理 Hook
|
|
67
67
|
|
|
68
68
|
### 2. 微前端架构
|
|
69
|
-
-
|
|
69
|
+
- 路由注册优先使用 `window.__MICO_PAGES__`(页面列表),无数据时降级到 `window.__MICO_MENUS__`(菜单树)
|
|
70
70
|
- 根据 `htmlUrl` 或 `jsUrls` 判断是否为微应用
|
|
71
71
|
- 使用 `loadMicroApp` API 动态挂载子应用
|
|
72
72
|
- 子应用共享主应用的 `request` 实例
|
|
73
|
+
- 权限通过菜单交叉引用 + 页面级兜底的双层策略控制
|
|
73
74
|
|
|
74
75
|
### 3. 主题系统
|
|
75
76
|
- 支持亮色/暗黑主题切换
|
|
76
77
|
- 使用 CSS Variables 实现运行时动态切换
|
|
77
|
-
- `arco-theme` 控制
|
|
78
|
+
- `arco-theme` 控制 @mico-platform/ui 组件
|
|
78
79
|
- `data-theme` 控制自定义样式
|
|
79
80
|
|
|
80
81
|
## 常用命令
|
|
@@ -123,6 +124,8 @@ Jenkins 根据环境执行 `CICD/` 下的构建脚本:
|
|
|
123
124
|
## 相关文档
|
|
124
125
|
|
|
125
126
|
- [微前端模式](mdc:apps/layout/docs/feature-微前端模式.md)
|
|
127
|
+
- [路由与菜单解耦](mdc:apps/layout/docs/feature-路由与菜单解耦.md)
|
|
128
|
+
- [菜单权限控制](mdc:apps/layout/docs/feature-菜单权限控制.md)
|
|
126
129
|
- [主题色切换](mdc:apps/layout/docs/feature-主题色切换.md)
|
|
127
130
|
- [提交规范](mdc:docs/commit-message.md)
|
|
128
131
|
- [部署说明](mdc:deployDesc.md)
|