generator-mico-cli 0.1.18
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 +84 -0
- package/bin/mico.js +316 -0
- package/generators/micro-react/ignore-list.json +8 -0
- package/generators/micro-react/index.js +158 -0
- package/generators/micro-react/templates/.commitlintrc.js +6 -0
- package/generators/micro-react/templates/.cursor/rules/always-read-docs.mdc +129 -0
- package/generators/micro-react/templates/.cursor/rules/cicd-deploy.mdc +143 -0
- package/generators/micro-react/templates/.cursor/rules/coding-conventions.mdc +206 -0
- package/generators/micro-react/templates/.cursor/rules/commit-conventions.mdc +111 -0
- package/generators/micro-react/templates/.cursor/rules/development-guide.mdc +295 -0
- package/generators/micro-react/templates/.cursor/rules/layout-app.mdc +275 -0
- package/generators/micro-react/templates/.cursor/rules/micro-frontend.mdc +196 -0
- package/generators/micro-react/templates/.cursor/rules/project-overview.mdc +128 -0
- package/generators/micro-react/templates/.cursor/rules/request-auth.mdc +220 -0
- package/generators/micro-react/templates/.cursor/rules/theme-system.mdc +206 -0
- package/generators/micro-react/templates/.editorconfig +16 -0
- package/generators/micro-react/templates/.env +3 -0
- package/generators/micro-react/templates/.eslintrc.js +30 -0
- package/generators/micro-react/templates/.husky/commit-msg +2 -0
- package/generators/micro-react/templates/.husky/pre-commit +2 -0
- package/generators/micro-react/templates/.lintstagedrc +5 -0
- package/generators/micro-react/templates/.stylelintrc.js +25 -0
- package/generators/micro-react/templates/AGENTS.md +39 -0
- package/generators/micro-react/templates/CICD/start_dev.sh +30 -0
- package/generators/micro-react/templates/CICD/start_local.sh +30 -0
- package/generators/micro-react/templates/CICD/start_prod.sh +30 -0
- package/generators/micro-react/templates/CICD/start_test.sh +30 -0
- package/generators/micro-react/templates/CICD/wangsu_fresh_dev.sh +19 -0
- package/generators/micro-react/templates/CICD/wangsu_fresh_prod.sh +19 -0
- package/generators/micro-react/templates/CICD/wangsu_fresh_test.sh +19 -0
- package/generators/micro-react/templates/CLAUDE.md +106 -0
- package/generators/micro-react/templates/README.md +84 -0
- package/generators/micro-react/templates/_gitignore +57 -0
- package/generators/micro-react/templates/_npmrc +2 -0
- package/generators/micro-react/templates/apps/layout/.env +4 -0
- package/generators/micro-react/templates/apps/layout/.eslintrc.js +10 -0
- package/generators/micro-react/templates/apps/layout/.lintstagedrc +17 -0
- package/generators/micro-react/templates/apps/layout/.prettierignore +3 -0
- package/generators/micro-react/templates/apps/layout/.prettierrc +8 -0
- package/generators/micro-react/templates/apps/layout/.stylelintrc.js +20 -0
- package/generators/micro-react/templates/apps/layout/README.md +37 -0
- package/generators/micro-react/templates/apps/layout/config/config.dev.ts +54 -0
- package/generators/micro-react/templates/apps/layout/config/config.prod.ts +37 -0
- package/generators/micro-react/templates/apps/layout/config/config.testing.ts +27 -0
- package/generators/micro-react/templates/apps/layout/config/config.ts +132 -0
- package/generators/micro-react/templates/apps/layout/config/routes.ts +13 -0
- package/generators/micro-react/templates/apps/layout/mock/api.mock.ts +78 -0
- package/generators/micro-react/templates/apps/layout/mock/menus.json +100 -0
- package/generators/micro-react/templates/apps/layout/mock/menus.ts +11 -0
- package/generators/micro-react/templates/apps/layout/mock/user.mock.ts +20 -0
- package/generators/micro-react/templates/apps/layout/package.json +45 -0
- package/generators/micro-react/templates/apps/layout/public/font/ar-SA.js +54 -0
- package/generators/micro-react/templates/apps/layout/public/font/default.js +54 -0
- package/generators/micro-react/templates/apps/layout/src/app.tsx +123 -0
- package/generators/micro-react/templates/apps/layout/src/assets/.gitkeep +0 -0
- package/generators/micro-react/templates/apps/layout/src/common/auth/cs-auth-manager.ts +220 -0
- package/generators/micro-react/templates/apps/layout/src/common/auth/index.ts +41 -0
- package/generators/micro-react/templates/apps/layout/src/common/auth/tool.ts +3 -0
- package/generators/micro-react/templates/apps/layout/src/common/auth/type.ts +6 -0
- package/generators/micro-react/templates/apps/layout/src/common/constants.ts +38 -0
- package/generators/micro-react/templates/apps/layout/src/common/env.ts +73 -0
- package/generators/micro-react/templates/apps/layout/src/common/helpers.ts +69 -0
- package/generators/micro-react/templates/apps/layout/src/common/locale.ts +123 -0
- package/generators/micro-react/templates/apps/layout/src/common/logger.ts +45 -0
- package/generators/micro-react/templates/apps/layout/src/common/menu/index.ts +2 -0
- package/generators/micro-react/templates/apps/layout/src/common/menu/parser.ts +143 -0
- package/generators/micro-react/templates/apps/layout/src/common/menu/types.ts +92 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/config.ts +73 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/index.ts +188 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/interceptors.ts +186 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/sso.ts +132 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/token-refresh.ts +136 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/types.ts +44 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/url-resolver.ts +75 -0
- package/generators/micro-react/templates/apps/layout/src/common/theme.ts +107 -0
- package/generators/micro-react/templates/apps/layout/src/common/types.ts +7 -0
- package/generators/micro-react/templates/apps/layout/src/common/upload/index.ts +2 -0
- package/generators/micro-react/templates/apps/layout/src/common/upload/oss.ts +401 -0
- package/generators/micro-react/templates/apps/layout/src/common/upload/types.ts +47 -0
- package/generators/micro-react/templates/apps/layout/src/common/uploadFiles.ts +35 -0
- package/generators/micro-react/templates/apps/layout/src/components/IconFont/index.tsx +25 -0
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.less +44 -0
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +121 -0
- package/generators/micro-react/templates/apps/layout/src/constants/index.ts +15 -0
- package/generators/micro-react/templates/apps/layout/src/global.less +13 -0
- package/generators/micro-react/templates/apps/layout/src/hooks/index.ts +3 -0
- package/generators/micro-react/templates/apps/layout/src/hooks/useAuth.ts +75 -0
- package/generators/micro-react/templates/apps/layout/src/hooks/useMenu.ts +35 -0
- package/generators/micro-react/templates/apps/layout/src/hooks/useMenuState.ts +112 -0
- package/generators/micro-react/templates/apps/layout/src/hooks/useTheme.ts +124 -0
- package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.less +109 -0
- package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.tsx +97 -0
- package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +164 -0
- package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +165 -0
- package/generators/micro-react/templates/apps/layout/src/layouts/index.less +71 -0
- package/generators/micro-react/templates/apps/layout/src/layouts/index.tsx +91 -0
- package/generators/micro-react/templates/apps/layout/src/locales/en-US.ts +20 -0
- package/generators/micro-react/templates/apps/layout/src/locales/zh-CN.ts +19 -0
- package/generators/micro-react/templates/apps/layout/src/models/global.ts +13 -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 -0
- package/generators/micro-react/templates/apps/layout/src/requestErrorConfig.ts +171 -0
- package/generators/micro-react/templates/apps/layout/src/services/auth.ts +37 -0
- package/generators/micro-react/templates/apps/layout/src/services/oss.ts +40 -0
- package/generators/micro-react/templates/apps/layout/src/styles/arco-override.less +78 -0
- package/generators/micro-react/templates/apps/layout/src/styles/themes/dark/custom-var.less +244 -0
- package/generators/micro-react/templates/apps/layout/src/styles/themes/normal/custom-var.less +195 -0
- package/generators/micro-react/templates/apps/layout/src/styles/variables.less +5 -0
- package/generators/micro-react/templates/apps/layout/src/utils/format.ts +4 -0
- package/generators/micro-react/templates/apps/layout/tailwind.config.js +7 -0
- package/generators/micro-react/templates/apps/layout/tailwind.css +3 -0
- package/generators/micro-react/templates/apps/layout/tsconfig.json +3 -0
- package/generators/micro-react/templates/apps/layout/typings.d.ts +1 -0
- package/generators/micro-react/templates/deployDesc.md +60 -0
- package/generators/micro-react/templates/docs/commit-message.md +98 -0
- package/generators/micro-react/templates/package.json +35 -0
- package/generators/micro-react/templates/packages/shared-styles/README.md +125 -0
- package/generators/micro-react/templates/packages/shared-styles/arco-override.less +78 -0
- package/generators/micro-react/templates/packages/shared-styles/index.less +14 -0
- package/generators/micro-react/templates/packages/shared-styles/package.json +27 -0
- package/generators/micro-react/templates/packages/shared-styles/theme-inject.less +10 -0
- package/generators/micro-react/templates/packages/shared-styles/themes/dark/custom-var.less +246 -0
- package/generators/micro-react/templates/packages/shared-styles/themes/normal/custom-var.less +195 -0
- package/generators/micro-react/templates/packages/shared-styles/variables-only.less +301 -0
- package/generators/micro-react/templates/packages/shared-styles/variables.less +363 -0
- package/generators/micro-react/templates/pnpm-workspace.yaml +9 -0
- package/generators/micro-react/templates/scripts/collect-dist.js +68 -0
- package/generators/micro-react/templates/scripts/create-umi-app.sh +61 -0
- package/generators/micro-react/templates/scripts/dev.js +133 -0
- package/generators/micro-react/templates/turbo.json +68 -0
- package/generators/subapp-react/ignore-list.json +7 -0
- package/generators/subapp-react/index.js +189 -0
- package/generators/subapp-react/templates/homepage/.env +4 -0
- package/generators/subapp-react/templates/homepage/README.md +116 -0
- package/generators/subapp-react/templates/homepage/_gitignore +9 -0
- package/generators/subapp-react/templates/homepage/config/config.dev.ts +59 -0
- package/generators/subapp-react/templates/homepage/config/config.prod.ts +41 -0
- package/generators/subapp-react/templates/homepage/config/config.testing.ts +40 -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/lib/utils.js +165 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Mico CLI Generator
|
|
2
|
+
|
|
3
|
+
用于搭建基于 TypeScript 的 Node.js CLI 项目的 Yeoman 生成器。
|
|
4
|
+
|
|
5
|
+
## 文档索引
|
|
6
|
+
|
|
7
|
+
| 文档 | 说明 |
|
|
8
|
+
|---|---|
|
|
9
|
+
| [docs/mico-cli.md](docs/mico-cli.md) | Mico CLI 功能概述与技术方案 |
|
|
10
|
+
| [docs/micro-react-generator.md](docs/micro-react-generator.md) | Monorepo 项目生成器说明 |
|
|
11
|
+
| [docs/subapp-react-generator.md](docs/subapp-react-generator.md) | React 子应用生成器说明 |
|
|
12
|
+
|
|
13
|
+
## 要求
|
|
14
|
+
|
|
15
|
+
- Node >= 18
|
|
16
|
+
- Yeoman CLI: `npm install -g yo`
|
|
17
|
+
|
|
18
|
+
## 安装和使用
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g yo generator-mico-cli
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 包装器 CLI
|
|
25
|
+
|
|
26
|
+
全局安装后,`mico` 命令可用于委托给 Yeoman 生成器。
|
|
27
|
+
如果 `generators/<name>` 下存在本地生成器,它将作为 `yo mico-cli:<name>` 运行。
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
mico create subapp-react
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
等同于:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
yo subapp-react
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
将额外参数传递给生成器:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
mico create micro-react -- --help
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Monorepo 项目生成器 (micro-react)
|
|
46
|
+
|
|
47
|
+
创建基于 qiankun 微前端架构的完整 Monorepo 项目:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
mkdir my-project && cd my-project
|
|
51
|
+
mico create micro-react
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
生成的项目包含:
|
|
55
|
+
- 主应用 (layout) - qiankun master
|
|
56
|
+
- 共享样式包 (shared-styles)
|
|
57
|
+
- Turborepo + pnpm Workspace
|
|
58
|
+
- Husky + Commitlint
|
|
59
|
+
|
|
60
|
+
## React 子应用生成器
|
|
61
|
+
|
|
62
|
+
该生成器会复制 `apps/homepage` 模板为新的子应用,并替换标识字符串。
|
|
63
|
+
`config/` 目录下的多环境配置会完整保留。
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
cd <monorepo-root>
|
|
67
|
+
mico create subapp-react
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 同步子应用模板
|
|
71
|
+
|
|
72
|
+
将源项目的 `apps/homepage` 同步到生成器模板目录:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
SOURCE_PROJECT_ROOT=<source-project-root> npm run sync:subapp-react-template
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
也可以直接传入路径:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm run sync:subapp-react-template -- <source-project-root>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
忽略清单位于 `generators/subapp-react/ignore-list.json`。
|
package/bin/mico.js
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { spawn, spawnSync } = require('node:child_process');
|
|
5
|
+
const fs = require('node:fs');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
const readline = require('node:readline');
|
|
8
|
+
|
|
9
|
+
const rootDir = path.resolve(__dirname, '..');
|
|
10
|
+
const pkg = JSON.parse(
|
|
11
|
+
fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8')
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 打印帮助信息
|
|
16
|
+
*/
|
|
17
|
+
function printHelp() {
|
|
18
|
+
console.log(`
|
|
19
|
+
Usage: mico <command> [options]
|
|
20
|
+
|
|
21
|
+
Commands:
|
|
22
|
+
create <generator> Run a generator (e.g., mico create subapp-react)
|
|
23
|
+
update Update mico-cli to the latest version
|
|
24
|
+
|
|
25
|
+
Options:
|
|
26
|
+
--help, -h Show this help message
|
|
27
|
+
--version, -v Show version number
|
|
28
|
+
--no-update-check Skip update check
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
mico create subapp-react
|
|
32
|
+
mico create app
|
|
33
|
+
mico update
|
|
34
|
+
|
|
35
|
+
Notes:
|
|
36
|
+
Requires Yeoman CLI (yo) installed globally.
|
|
37
|
+
If a local generator exists at generators/<name>, it will be used.
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 打印版本信息
|
|
43
|
+
*/
|
|
44
|
+
function printVersion() {
|
|
45
|
+
console.log(`mico-cli v${pkg.version}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 检查是否有新版本
|
|
50
|
+
* @returns {Promise<{current: string, latest: string, hasUpdate: boolean} | null>}
|
|
51
|
+
*/
|
|
52
|
+
async function checkForUpdate() {
|
|
53
|
+
try {
|
|
54
|
+
const updateNotifier = (await import('update-notifier')).default;
|
|
55
|
+
const semver = (await import('semver')).default;
|
|
56
|
+
const notifier = updateNotifier({
|
|
57
|
+
pkg,
|
|
58
|
+
updateCheckInterval: 0 // 每次都检查
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// 等待检查完成
|
|
62
|
+
await notifier.fetchInfo();
|
|
63
|
+
|
|
64
|
+
// 使用 semver 比较,确保 latest > current
|
|
65
|
+
if (notifier.update && semver.gt(notifier.update.latest, pkg.version)) {
|
|
66
|
+
return {
|
|
67
|
+
current: pkg.version,
|
|
68
|
+
latest: notifier.update.latest,
|
|
69
|
+
hasUpdate: true
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return { current: pkg.version, latest: pkg.version, hasUpdate: false };
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 询问用户是否更新
|
|
80
|
+
* @returns {Promise<boolean>}
|
|
81
|
+
*/
|
|
82
|
+
function askForUpdate(current, latest) {
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
const rl = readline.createInterface({
|
|
85
|
+
input: process.stdin,
|
|
86
|
+
output: process.stdout
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log(` 📦 New version available: ${current} → \x1b[32m${latest}\x1b[0m`);
|
|
91
|
+
rl.question(' Do you want to update now? (Y/n) ', (answer) => {
|
|
92
|
+
rl.close();
|
|
93
|
+
const normalized = answer.trim().toLowerCase();
|
|
94
|
+
resolve(normalized === '' || normalized === 'y' || normalized === 'yes');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 检测当前使用的包管理器
|
|
101
|
+
* 通过检查可执行文件的安装路径来判断
|
|
102
|
+
* @returns {'npm' | 'pnpm' | 'yarn'}
|
|
103
|
+
*/
|
|
104
|
+
function detectPackageManager() {
|
|
105
|
+
// 首先检查环境变量(通过包管理器脚本运行时有效)
|
|
106
|
+
const npmUserAgent = process.env.npm_config_user_agent || '';
|
|
107
|
+
if (npmUserAgent.includes('pnpm')) return 'pnpm';
|
|
108
|
+
if (npmUserAgent.includes('yarn')) return 'yarn';
|
|
109
|
+
|
|
110
|
+
// 检查当前脚本的安装路径
|
|
111
|
+
// pnpm 全局安装路径通常包含: pnpm, .local/share/pnpm, Library/pnpm
|
|
112
|
+
const scriptPath = process.argv[1] || '';
|
|
113
|
+
const scriptPathLower = scriptPath.toLowerCase();
|
|
114
|
+
if (
|
|
115
|
+
scriptPathLower.includes('pnpm') ||
|
|
116
|
+
scriptPathLower.includes('.local/share/pnpm') ||
|
|
117
|
+
scriptPathLower.includes('library/pnpm')
|
|
118
|
+
) {
|
|
119
|
+
return 'pnpm';
|
|
120
|
+
}
|
|
121
|
+
if (scriptPathLower.includes('yarn')) return 'yarn';
|
|
122
|
+
|
|
123
|
+
// 检查 rootDir 路径(当前包的安装位置)
|
|
124
|
+
const rootDirLower = rootDir.toLowerCase();
|
|
125
|
+
if (
|
|
126
|
+
rootDirLower.includes('pnpm') ||
|
|
127
|
+
rootDirLower.includes('.local/share/pnpm') ||
|
|
128
|
+
rootDirLower.includes('library/pnpm')
|
|
129
|
+
) {
|
|
130
|
+
return 'pnpm';
|
|
131
|
+
}
|
|
132
|
+
if (rootDirLower.includes('yarn')) return 'yarn';
|
|
133
|
+
|
|
134
|
+
// 默认使用 npm
|
|
135
|
+
return 'npm';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 执行更新
|
|
140
|
+
* @param {string} latestVersion - 要更新到的版本号
|
|
141
|
+
* @returns {boolean} 是否更新成功
|
|
142
|
+
*/
|
|
143
|
+
function performUpdate(latestVersion) {
|
|
144
|
+
console.log('');
|
|
145
|
+
console.log(' ⏳ Updating mico-cli...');
|
|
146
|
+
|
|
147
|
+
// 检测包管理器
|
|
148
|
+
const pm = detectPackageManager();
|
|
149
|
+
|
|
150
|
+
// 指定具体版本号,避免缓存问题
|
|
151
|
+
const packageSpec = latestVersion ? `${pkg.name}@${latestVersion}` : `${pkg.name}@latest`;
|
|
152
|
+
|
|
153
|
+
// 执行全局安装
|
|
154
|
+
const installCmd = pm === 'yarn' ? 'yarn' : pm;
|
|
155
|
+
const installArgs =
|
|
156
|
+
pm === 'yarn'
|
|
157
|
+
? ['global', 'add', packageSpec]
|
|
158
|
+
: ['install', '-g', packageSpec];
|
|
159
|
+
|
|
160
|
+
console.log(` Using ${pm} to install ${packageSpec}`);
|
|
161
|
+
|
|
162
|
+
const result = spawnSync(installCmd, installArgs, {
|
|
163
|
+
stdio: 'inherit',
|
|
164
|
+
shell: process.platform === 'win32'
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if (result.status === 0) {
|
|
168
|
+
console.log('');
|
|
169
|
+
console.log(' ✅ Update successful! Please re-run your command.');
|
|
170
|
+
return true;
|
|
171
|
+
} else {
|
|
172
|
+
console.log('');
|
|
173
|
+
console.log(' ❌ Update failed. Please try manually:');
|
|
174
|
+
console.log(` ${installCmd} ${installArgs.join(' ')}`);
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* 运行 Yeoman 生成器
|
|
181
|
+
*/
|
|
182
|
+
function runGenerator(generator, rest, passthroughArgs) {
|
|
183
|
+
const localGeneratorEntry = path.join(
|
|
184
|
+
rootDir,
|
|
185
|
+
'generators',
|
|
186
|
+
generator,
|
|
187
|
+
'index.js'
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
const pkgName = typeof pkg.name === 'string' ? pkg.name : '';
|
|
191
|
+
const localNamespace =
|
|
192
|
+
pkgName.replace(/^generator-/, '') || pkgName || 'generator';
|
|
193
|
+
|
|
194
|
+
const yoGenerator = fs.existsSync(localGeneratorEntry)
|
|
195
|
+
? `${localNamespace}:${generator}`
|
|
196
|
+
: generator;
|
|
197
|
+
|
|
198
|
+
const yoArgs = [yoGenerator, ...rest];
|
|
199
|
+
|
|
200
|
+
if (passthroughArgs.length > 0) {
|
|
201
|
+
yoArgs.push('--', ...passthroughArgs);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const child = spawn('yo', yoArgs, { stdio: 'inherit' });
|
|
205
|
+
|
|
206
|
+
child.on('error', (error) => {
|
|
207
|
+
if (error && error.code === 'ENOENT') {
|
|
208
|
+
console.error('Cannot find "yo". Install it with: npm install -g yo');
|
|
209
|
+
} else {
|
|
210
|
+
console.error(error);
|
|
211
|
+
}
|
|
212
|
+
process.exit(1);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
child.on('exit', (code) => {
|
|
216
|
+
process.exit(typeof code === 'number' ? code : 1);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 主函数
|
|
222
|
+
*/
|
|
223
|
+
async function main() {
|
|
224
|
+
const args = process.argv.slice(2);
|
|
225
|
+
|
|
226
|
+
// 解析参数
|
|
227
|
+
const doubleDashIndex = args.indexOf('--');
|
|
228
|
+
const passthroughArgs =
|
|
229
|
+
doubleDashIndex === -1 ? [] : args.slice(doubleDashIndex + 1);
|
|
230
|
+
const mainArgs =
|
|
231
|
+
doubleDashIndex === -1 ? args : args.slice(0, doubleDashIndex);
|
|
232
|
+
|
|
233
|
+
// 检查特殊标志
|
|
234
|
+
const hasHelp = mainArgs.includes('--help') || mainArgs.includes('-h');
|
|
235
|
+
const hasVersion = mainArgs.includes('--version') || mainArgs.includes('-v');
|
|
236
|
+
const skipUpdateCheck = mainArgs.includes('--no-update-check');
|
|
237
|
+
|
|
238
|
+
// 过滤掉标志参数
|
|
239
|
+
const filteredArgs = mainArgs.filter(
|
|
240
|
+
(arg) =>
|
|
241
|
+
arg !== '--help' &&
|
|
242
|
+
arg !== '-h' &&
|
|
243
|
+
arg !== '--version' &&
|
|
244
|
+
arg !== '-v' &&
|
|
245
|
+
arg !== '--no-update-check'
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
// 处理 --version
|
|
249
|
+
if (hasVersion) {
|
|
250
|
+
printVersion();
|
|
251
|
+
process.exit(0);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// 处理 --help 或无参数
|
|
255
|
+
if (hasHelp || filteredArgs.length === 0) {
|
|
256
|
+
printHelp();
|
|
257
|
+
process.exit(0);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const [command, ...rest] = filteredArgs;
|
|
261
|
+
|
|
262
|
+
// 处理 update 命令
|
|
263
|
+
if (command === 'update') {
|
|
264
|
+
const updateInfo = await checkForUpdate();
|
|
265
|
+
if (updateInfo && updateInfo.hasUpdate) {
|
|
266
|
+
performUpdate(updateInfo.latest);
|
|
267
|
+
} else if (updateInfo) {
|
|
268
|
+
console.log(` ✅ You are using the latest version (v${updateInfo.current})`);
|
|
269
|
+
} else {
|
|
270
|
+
console.log(' ⚠️ Could not check for updates');
|
|
271
|
+
}
|
|
272
|
+
process.exit(0);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// 处理 create 命令
|
|
276
|
+
if (command === 'create') {
|
|
277
|
+
const generator = rest[0];
|
|
278
|
+
if (!generator) {
|
|
279
|
+
printHelp();
|
|
280
|
+
process.exit(1);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// 检查更新(除非跳过)
|
|
284
|
+
if (!skipUpdateCheck) {
|
|
285
|
+
const updateInfo = await checkForUpdate();
|
|
286
|
+
if (updateInfo && updateInfo.hasUpdate) {
|
|
287
|
+
const shouldUpdate = await askForUpdate(
|
|
288
|
+
updateInfo.current,
|
|
289
|
+
updateInfo.latest
|
|
290
|
+
);
|
|
291
|
+
if (shouldUpdate) {
|
|
292
|
+
const success = performUpdate(updateInfo.latest);
|
|
293
|
+
if (success) {
|
|
294
|
+
process.exit(0);
|
|
295
|
+
}
|
|
296
|
+
// 更新失败则继续执行
|
|
297
|
+
}
|
|
298
|
+
console.log('');
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// 运行生成器
|
|
303
|
+
runGenerator(generator, rest.slice(1), passthroughArgs);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// 未知命令
|
|
308
|
+
console.error(`Unknown command: ${command}`);
|
|
309
|
+
printHelp();
|
|
310
|
+
process.exit(1);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
main().catch((err) => {
|
|
314
|
+
console.error(err);
|
|
315
|
+
process.exit(1);
|
|
316
|
+
});
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Generator = require('yeoman-generator');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const {
|
|
7
|
+
toKebab,
|
|
8
|
+
toPascal,
|
|
9
|
+
collectFiles,
|
|
10
|
+
transformDestPath,
|
|
11
|
+
isTemplateFile,
|
|
12
|
+
setupErrorHandlers
|
|
13
|
+
} = require('../../lib/utils');
|
|
14
|
+
|
|
15
|
+
const IGNORE_LIST = require('./ignore-list.json');
|
|
16
|
+
|
|
17
|
+
// 安装全局错误处理
|
|
18
|
+
setupErrorHandlers();
|
|
19
|
+
|
|
20
|
+
module.exports = class extends Generator {
|
|
21
|
+
initializing() {
|
|
22
|
+
this.projectRoot = process.cwd();
|
|
23
|
+
|
|
24
|
+
// 检查当前目录是否已是一个 monorepo
|
|
25
|
+
const workspaceFile = path.join(this.projectRoot, 'pnpm-workspace.yaml');
|
|
26
|
+
if (fs.existsSync(workspaceFile)) {
|
|
27
|
+
console.error('');
|
|
28
|
+
console.error('❌ Error: Current directory is already a monorepo.');
|
|
29
|
+
console.error('');
|
|
30
|
+
console.error(' A pnpm-workspace.yaml file already exists.');
|
|
31
|
+
console.error(' Please run this command in an empty directory or specify a new project name.');
|
|
32
|
+
console.error('');
|
|
33
|
+
console.error(' Usage:');
|
|
34
|
+
console.error(' mkdir my-project && cd my-project');
|
|
35
|
+
console.error(' mico create micro-react');
|
|
36
|
+
console.error('');
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async prompting() {
|
|
42
|
+
try {
|
|
43
|
+
this.answers = await this.prompt([
|
|
44
|
+
{
|
|
45
|
+
type: 'input',
|
|
46
|
+
name: 'projectName',
|
|
47
|
+
message: 'Project name',
|
|
48
|
+
default: path.basename(this.projectRoot),
|
|
49
|
+
filter: (input) => toKebab(input),
|
|
50
|
+
validate: (input) => {
|
|
51
|
+
const value = toKebab(input);
|
|
52
|
+
if (!value) return 'Project name is required';
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
type: 'input',
|
|
58
|
+
name: 'packageScope',
|
|
59
|
+
message: 'Package scope (e.g., @my-project)',
|
|
60
|
+
default: (answers) => `@${toKebab(answers.projectName)}`,
|
|
61
|
+
validate: (input) => {
|
|
62
|
+
if (!input) return 'Package scope is required';
|
|
63
|
+
if (!input.startsWith('@')) return 'Package scope must start with @';
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: 'input',
|
|
69
|
+
name: 'author',
|
|
70
|
+
message: 'Author',
|
|
71
|
+
default: 'Your Name <email@example.com>'
|
|
72
|
+
}
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
this.projectName = toKebab(this.answers.projectName);
|
|
76
|
+
this.ProjectName = toPascal(this.projectName);
|
|
77
|
+
this.packageScope = this.answers.packageScope;
|
|
78
|
+
this.author = this.answers.author;
|
|
79
|
+
this.templateDir = this.templatePath();
|
|
80
|
+
this.destDir = this.projectRoot;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error('');
|
|
83
|
+
console.error('❌ Error during prompting:');
|
|
84
|
+
console.error(` ${error.message}`);
|
|
85
|
+
console.error('');
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
writing() {
|
|
91
|
+
try {
|
|
92
|
+
if (!fs.existsSync(this.templateDir)) {
|
|
93
|
+
console.error('');
|
|
94
|
+
console.error('❌ Error: Template directory not found.');
|
|
95
|
+
console.error(` Expected: ${this.templateDir}`);
|
|
96
|
+
console.error('');
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const templateData = {
|
|
101
|
+
projectName: this.projectName,
|
|
102
|
+
ProjectName: this.ProjectName,
|
|
103
|
+
packageScope: this.packageScope,
|
|
104
|
+
author: this.author
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const files = collectFiles(this.templateDir, this.templateDir, IGNORE_LIST);
|
|
108
|
+
|
|
109
|
+
if (files.length === 0) {
|
|
110
|
+
console.error('');
|
|
111
|
+
console.error('❌ Error: No template files found.');
|
|
112
|
+
console.error(` Template directory: ${this.templateDir}`);
|
|
113
|
+
console.error('');
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
this.log('');
|
|
118
|
+
this.log(`📦 Creating project: ${this.projectName}`);
|
|
119
|
+
this.log(` Scope: ${this.packageScope}`);
|
|
120
|
+
this.log('');
|
|
121
|
+
|
|
122
|
+
for (const relPath of files) {
|
|
123
|
+
const srcPath = path.join(this.templateDir, relPath);
|
|
124
|
+
const destRelPath = transformDestPath(relPath);
|
|
125
|
+
const destPath = path.join(this.destDir, destRelPath);
|
|
126
|
+
|
|
127
|
+
if (isTemplateFile(relPath)) {
|
|
128
|
+
this.fs.copyTpl(srcPath, destPath, templateData);
|
|
129
|
+
} else {
|
|
130
|
+
this.fs.copy(srcPath, destPath);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error('');
|
|
135
|
+
console.error('❌ Error during file generation:');
|
|
136
|
+
console.error(` ${error.message}`);
|
|
137
|
+
console.error('');
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
end() {
|
|
143
|
+
this.log('');
|
|
144
|
+
this.log('✅ 项目创建成功!');
|
|
145
|
+
this.log('');
|
|
146
|
+
this.log(' 后续步骤:');
|
|
147
|
+
this.log('');
|
|
148
|
+
this.log(' # 安装依赖');
|
|
149
|
+
this.log(' pnpm install');
|
|
150
|
+
this.log('');
|
|
151
|
+
this.log(' # 启动开发服务器');
|
|
152
|
+
this.log(' pnpm dev');
|
|
153
|
+
this.log('');
|
|
154
|
+
this.log(' # 创建新的子应用');
|
|
155
|
+
this.log(' mico create subapp-react');
|
|
156
|
+
this.log('');
|
|
157
|
+
}
|
|
158
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: 开发前必读 - 强制查阅项目文档
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 开发前必读文档
|
|
7
|
+
|
|
8
|
+
## ⚠️ 重要规则
|
|
9
|
+
|
|
10
|
+
**在开始任何开发需求之前,必须先查阅相关文档!**
|
|
11
|
+
|
|
12
|
+
## 📚 文档位置
|
|
13
|
+
|
|
14
|
+
### 1. 项目级文档 (`/docs/`)
|
|
15
|
+
```
|
|
16
|
+
docs/
|
|
17
|
+
└── commit-message.md # Git 提交规范
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. Layout 应用文档 (`/apps/layout/docs/`)
|
|
21
|
+
```
|
|
22
|
+
apps/layout/docs/
|
|
23
|
+
├── feature-微前端模式.md # qiankun 微前端架构
|
|
24
|
+
└── feature-主题色切换.md # 主题系统实现
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 3. 其他应用文档
|
|
28
|
+
每个子应用可能在 `apps/<app>/docs/` 下有功能文档。
|
|
29
|
+
|
|
30
|
+
## 🔍 开发前检查清单
|
|
31
|
+
|
|
32
|
+
在开始开发需求时,请按以下步骤操作:
|
|
33
|
+
|
|
34
|
+
### Step 1: 确认需求涉及的模块
|
|
35
|
+
- 微前端相关 → 阅读 `apps/layout/docs/feature-微前端模式.md`
|
|
36
|
+
- 主题/样式相关 → 阅读 `apps/layout/docs/feature-主题色切换.md`
|
|
37
|
+
- 请求/认证相关 → 阅读 `src/common/request/` 和 `src/common/auth/` 源码
|
|
38
|
+
- 菜单相关 → 阅读 `src/common/menu/` 源码
|
|
39
|
+
|
|
40
|
+
### Step 2: 查找相关文档
|
|
41
|
+
```bash
|
|
42
|
+
# 搜索 docs 目录
|
|
43
|
+
find . -path "*/docs/*.md" -type f
|
|
44
|
+
|
|
45
|
+
# 搜索所有 markdown 文档
|
|
46
|
+
find . -name "*.md" -type f | grep -v node_modules
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Step 3: 阅读相关源码目录的 README
|
|
50
|
+
某些目录下可能有 `README.md` 或 `index.ts` 中的注释说明。
|
|
51
|
+
|
|
52
|
+
## 📋 常用文档速查
|
|
53
|
+
|
|
54
|
+
| 需求类型 | 必读文档 |
|
|
55
|
+
|---------|---------|
|
|
56
|
+
| 新建子应用 | `apps/layout/docs/feature-微前端模式.md` |
|
|
57
|
+
| 主题适配 | `apps/layout/docs/feature-主题色切换.md` |
|
|
58
|
+
| 提交代码 | `docs/commit-message.md` |
|
|
59
|
+
| API 请求 | `src/common/request/index.ts` 源码注释 |
|
|
60
|
+
| 认证登录 | `src/common/auth/` 目录源码 |
|
|
61
|
+
| 菜单配置 | `src/common/menu/types.ts` 类型定义 |
|
|
62
|
+
|
|
63
|
+
## 🚨 AI 助手行为要求
|
|
64
|
+
|
|
65
|
+
1. **接收到开发需求时**:
|
|
66
|
+
- 首先识别需求涉及哪些模块
|
|
67
|
+
- 使用 `list_dir` 查看对应目录是否有 docs 文件夹
|
|
68
|
+
- 使用 `read_file` 阅读相关文档
|
|
69
|
+
- 阅读相关源码理解现有实现
|
|
70
|
+
|
|
71
|
+
2. **修改现有功能时**:
|
|
72
|
+
- 先阅读该功能的现有代码
|
|
73
|
+
- 查找是否有对应的文档说明
|
|
74
|
+
- 理解设计意图后再进行修改
|
|
75
|
+
|
|
76
|
+
3. **新增功能时**:
|
|
77
|
+
- 参考类似功能的实现方式
|
|
78
|
+
- 遵循项目现有的代码风格和架构模式
|
|
79
|
+
- 考虑是否需要同步更新文档
|
|
80
|
+
|
|
81
|
+
## 📝 文档模板
|
|
82
|
+
|
|
83
|
+
新功能开发完成后,建议创建对应文档:
|
|
84
|
+
|
|
85
|
+
```markdown
|
|
86
|
+
# 功能名称
|
|
87
|
+
|
|
88
|
+
> 创建时间:YYYY-MM-DD
|
|
89
|
+
|
|
90
|
+
## 功能概述
|
|
91
|
+
|
|
92
|
+
简要描述功能用途。
|
|
93
|
+
|
|
94
|
+
## 技术方案
|
|
95
|
+
|
|
96
|
+
### 技术栈
|
|
97
|
+
- 列出使用的技术
|
|
98
|
+
|
|
99
|
+
### 核心实现
|
|
100
|
+
1. 实现步骤 1
|
|
101
|
+
2. 实现步骤 2
|
|
102
|
+
|
|
103
|
+
## 文件清单
|
|
104
|
+
|
|
105
|
+
| 文件路径 | 说明 |
|
|
106
|
+
|---------|------|
|
|
107
|
+
| `src/xxx` | 描述 |
|
|
108
|
+
|
|
109
|
+
## API / 组件接口
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// 接口定义
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## 使用示例
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
// 代码示例
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## 注意事项
|
|
122
|
+
|
|
123
|
+
- 注意点 1
|
|
124
|
+
- 注意点 2
|
|
125
|
+
|
|
126
|
+
## 相关文档
|
|
127
|
+
|
|
128
|
+
- [相关文档 1](./xxx.md)
|
|
129
|
+
```
|