@itbox/cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +208 -0
  2. package/bin/index.js +316 -0
  3. package/package.json +38 -0
package/README.md ADDED
@@ -0,0 +1,208 @@
1
+ # @itbox/cli
2
+
3
+ 前端项目模板生成工具,支持Vue、Vue+TypeScript、Nuxt、Nest等多种模板,可从Gitee动态拉取模板分支。
4
+
5
+ ## 功能特性
6
+
7
+ - ✅ 支持从Gitee仓库动态获取模板分支
8
+ - ✅ 支持npm/pnpm包管理器选择
9
+ - ✅ 交互式终端操作(方向键切换,空格选择)
10
+ - ✅ 配置管理功能(支持设置模板仓库地址)
11
+ - ✅ 列出所有可用模板功能
12
+ - ✅ ES模块模式开发
13
+ - ✅ 支持 `pnpm create itbox` 调用方式
14
+
15
+ ## 安装
16
+
17
+ ### 全局安装
18
+
19
+ ```bash
20
+ # 使用 npm
21
+ npm install -g @itbox/cli
22
+
23
+ # 使用 pnpm
24
+ pnpm add -g @itbox/cli
25
+ ```
26
+
27
+ ### 直接使用
28
+
29
+ ```bash
30
+ # 使用 npm create
31
+ npm create itbox <项目名>
32
+
33
+ # 使用 pnpm create
34
+ pnpm create itbox <项目名>
35
+ ```
36
+
37
+ ## 使用方法
38
+
39
+ ### 创建项目
40
+
41
+ ```bash
42
+ # 使用命令创建项目
43
+ itbox create <项目名>
44
+
45
+ # 示例
46
+ itbox create my-vue3-app
47
+ ```
48
+
49
+ 执行后会进入交互式选择界面:
50
+ 1. 选择项目模板(从Gitee仓库动态获取的分支)
51
+ 2. 选择包管理器(npm或pnpm)
52
+
53
+ ### 列出所有可用模板
54
+
55
+ ```bash
56
+ itbox list
57
+ ```
58
+
59
+ ### 配置管理
60
+
61
+ ```bash
62
+ # 设置模板仓库地址
63
+ itbox config set templateRepo <仓库地址>
64
+
65
+ # 获取当前模板仓库地址
66
+ itbox config get templateRepo
67
+
68
+ # 删除模板仓库配置
69
+ itbox config delete templateRepo
70
+
71
+ # 查看配置帮助
72
+ itbox config help
73
+ ```
74
+
75
+ ## 命令详解
76
+
77
+ ### `itbox create <projectName>`
78
+
79
+ 创建新的前端项目,从指定Gitee仓库拉取模板。
80
+
81
+ **参数:**
82
+ - `projectName`: 项目名称,将作为新创建的项目目录名
83
+
84
+ **功能流程:**
85
+ 1. 检查Git是否安装
86
+ 2. 获取远程仓库分支列表作为模板选项
87
+ 3. 交互式选择模板和包管理器
88
+ 4. 检查包管理器是否安装
89
+ 5. 使用git clone命令下载模板
90
+ 6. 安装项目依赖
91
+
92
+ ### `itbox list`
93
+
94
+ 列出所有可用的项目模板(即远程仓库的分支列表)。
95
+
96
+ **功能流程:**
97
+ 1. 检查Git是否安装
98
+ 2. 获取远程仓库分支列表
99
+ 3. 格式化输出模板列表
100
+
101
+ ### `itbox config`
102
+
103
+ 管理CLI工具的配置项。
104
+
105
+ **子命令:**
106
+ - `set <key> <value>`: 设置配置项
107
+ - `get <key>`: 获取配置项值
108
+ - `delete <key>`: 删除配置项
109
+ - `help`: 显示配置命令帮助
110
+
111
+ **配置文件位置:**
112
+ `~/.fe-cli/config.json`
113
+
114
+ **可配置项:**
115
+ - `templateRepo`: 模板仓库地址(默认:https://gitee.com/jianlidmeng/template.git)
116
+
117
+ ## 实现逻辑
118
+
119
+ ### 技术栈
120
+
121
+ - **Node.js**: 运行环境
122
+ - **Commander.js**: 命令行界面构建
123
+ - **Inquirer.js**: 交互式终端实现
124
+ - **Git**: 模板下载和分支获取
125
+ - **fs-extra**: 文件系统操作
126
+ - **ora**: 终端加载动画
127
+
128
+ ### 核心实现
129
+
130
+ 1. **动态模板获取**
131
+ - 使用 `git ls-remote --heads` 命令获取远程仓库分支列表
132
+ - 分支名称作为模板选项供用户选择
133
+
134
+ 2. **模板下载**
135
+ - 使用 `git clone -b <branch> <repo> <projectName>` 命令直接克隆指定分支
136
+ - 替代了传统的 `download-git-repo` 库,解决了Gitee兼容性问题
137
+
138
+ 3. **交互式选择**
139
+ - 使用 Inquirer.js 的 checkbox 类型实现单选限制
140
+ - 通过 validate 函数确保只能选择一个模板和一个包管理器
141
+ - 支持方向键切换、空格选择、回车确认
142
+
143
+ 4. **配置管理**
144
+ - 配置文件存储在用户主目录下的 `.fe-cli/config.json`
145
+ - 实现了完整的配置读写功能
146
+ - 支持多个配置项的管理
147
+
148
+ 5. **模块化设计**
149
+ - 使用 ES 模块模式开发(package.json 中设置 `"type": "module"`)
150
+ - 功能模块化,便于维护和扩展
151
+
152
+ ### 项目结构
153
+
154
+ ```
155
+ @itbox/cli/
156
+ ├── bin/
157
+ │ └── index.js # CLI入口文件
158
+ ├── package.json # 项目配置文件
159
+ └── README.md # 项目文档
160
+ ```
161
+
162
+ ## 注意事项
163
+
164
+ 1. **Git安装**:使用前请确保已安装Git
165
+ 2. **包管理器**:根据选择的包管理器确保已安装
166
+ 3. **网络连接**:需要网络连接以获取模板列表和下载模板
167
+ 4. **仓库权限**:确保Gitee仓库是公开的,或已登录Git账号
168
+
169
+ ## 故障排除
170
+
171
+ ### 1. Git命令失败
172
+
173
+ **错误信息**:`git clone failed with status 128`
174
+
175
+ **解决方案**:
176
+ - 检查Git是否正确安装:`git --version`
177
+ - 检查网络连接是否正常
178
+ - 确保Gitee仓库是公开的或已正确配置Git凭证
179
+
180
+ ### 2. 模板列表获取失败
181
+
182
+ **错误信息**:`403 Forbidden`
183
+
184
+ **解决方案**:
185
+ - 检查Git是否已登录Gitee账号
186
+ - 确保仓库具有公开访问权限
187
+ - 尝试重新配置模板仓库地址
188
+
189
+ ### 3. 包管理器命令失败
190
+
191
+ **错误信息**:`Command not found`
192
+
193
+ **解决方案**:
194
+ - 安装选择的包管理器:`npm install -g npm` 或 `npm install -g pnpm`
195
+ - 检查包管理器是否在系统PATH中
196
+
197
+ ## 更新日志
198
+
199
+ ### v1.0.0
200
+ - 初始版本发布
201
+ - 支持从Gitee动态获取模板分支
202
+ - 支持npm/pnpm包管理器选择
203
+ - 实现配置管理功能
204
+ - 支持 `pnpm create itbox` 调用方式
205
+
206
+ ## License
207
+
208
+ MIT
package/bin/index.js ADDED
@@ -0,0 +1,316 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import inquirer from 'inquirer';
4
+ import fs from 'fs-extra';
5
+ import path from 'path';
6
+ import ora from 'ora';
7
+ import { execSync } from 'child_process';
8
+ import os from 'os';
9
+
10
+ const { prompt } = inquirer;
11
+
12
+ // 配置文件相关
13
+ const CONFIG_DIR = path.join(os.homedir(), '.fe-cli');
14
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
15
+
16
+ // 读取配置
17
+ function readConfig() {
18
+ if (fs.existsSync(CONFIG_FILE)) {
19
+ try {
20
+ return fs.readJSONSync(CONFIG_FILE);
21
+ } catch (error) {
22
+ console.error('❌ 读取配置文件失败:', error.message);
23
+ return {};
24
+ }
25
+ }
26
+ return {};
27
+ }
28
+
29
+ // 写入配置
30
+ function writeConfig(config) {
31
+ try {
32
+ // 确保配置目录存在
33
+ fs.ensureDirSync(CONFIG_DIR);
34
+ fs.writeJSONSync(CONFIG_FILE, config, { spaces: 2 });
35
+ return true;
36
+ } catch (error) {
37
+ console.error('❌ 写入配置文件失败:', error.message);
38
+ return false;
39
+ }
40
+ }
41
+
42
+ // 获取配置项
43
+ function getConfig(key) {
44
+ const config = readConfig();
45
+ return config[key];
46
+ }
47
+
48
+ // 设置配置项
49
+ function setConfig(key, value) {
50
+ const config = readConfig();
51
+ config[key] = value;
52
+ return writeConfig(config);
53
+ }
54
+
55
+ // 创建命令行程序实例
56
+ const program = new Command();
57
+
58
+ // 检查git是否安装
59
+ function checkGit() {
60
+ try {
61
+ execSync('git --version', { stdio: 'ignore' });
62
+ return true;
63
+ } catch (error) {
64
+ return false;
65
+ }
66
+ }
67
+
68
+ // 检查包管理器是否安装
69
+ function checkPackageManager(pm) {
70
+ try {
71
+ execSync(`${pm} --version`, { stdio: 'ignore' });
72
+ return true;
73
+ } catch (error) {
74
+ return false;
75
+ }
76
+ }
77
+
78
+ // 获取远程仓库分支
79
+ function getRemoteBranches(repoUrl) {
80
+ try {
81
+ const output = execSync(`git ls-remote --heads ${repoUrl}`, { stdio: 'pipe' });
82
+ const branches = output.toString().split('\n').filter(line => line.trim()).map(line => {
83
+ const [, ref] = line.split('\t');
84
+ return ref.replace('refs/heads/', '');
85
+ });
86
+ return branches;
87
+ } catch (error) {
88
+ if (error.message.includes('403')) {
89
+ console.error('❌ 仓库访问受限 (403)');
90
+ console.error('请检查:');
91
+ console.error('1. 是否已登录Gitee');
92
+ console.error('2. 是否有权限访问该仓库');
93
+ console.error('3. 仓库是否处于公开状态');
94
+ } else {
95
+ console.error('❌ 获取远程分支失败:', error.message);
96
+ }
97
+ process.exit(1);
98
+ }
99
+ }
100
+
101
+
102
+
103
+ // 指定的gitee仓库(优先从配置文件读取,否则使用默认值)
104
+ const DEFAULT_TEMPLATE_REPO = 'https://gitee.com/jianlidmeng/template.git';
105
+ let TEMPLATE_REPO = getConfig('templateRepo') || DEFAULT_TEMPLATE_REPO;
106
+
107
+ // 从package.json获取项目信息
108
+ const packagePath = path.resolve(path.dirname(import.meta.url.replace('file:///', '')), '../package.json');
109
+ const packageInfo = fs.readJSONSync(packagePath);
110
+
111
+ // 命令行配置
112
+ program
113
+ .name(packageInfo.name.split('/')[1]) // 使用包名的第二部分作为命令名(如@itbox/cli -> itbox)
114
+ .description(packageInfo.description)
115
+ .version(packageInfo.version);
116
+
117
+ // 列出所有可用模板
118
+ program
119
+ .command('list')
120
+ .description('列出所有可用的项目模板')
121
+ .action(() => {
122
+ // 检查git是否安装
123
+ if (!checkGit()) {
124
+ console.error('❌ 请先安装Git');
125
+ process.exit(1);
126
+ }
127
+
128
+ // 获取远程仓库分支(模板)
129
+ const spinner = ora('正在获取可用模板列表...').start();
130
+ const branches = getRemoteBranches(TEMPLATE_REPO);
131
+ spinner.succeed('✅ 模板列表获取完成');
132
+
133
+ // 显示模板列表
134
+ if (branches.length === 0) {
135
+ console.log('❌ 当前仓库没有可用的模板');
136
+ } else {
137
+ console.log('\n🚀 可用模板列表:');
138
+ console.log('================');
139
+ branches.forEach((branch, index) => {
140
+ console.log(`${index + 1}. ${branch}`);
141
+ });
142
+ console.log('================');
143
+ console.log(`\n共 ${branches.length} 个可用模板`);
144
+ console.log('\n使用命令创建项目: itbox create <项目名>');
145
+ console.log('或使用: pnpm create itbox <项目名>');
146
+ }
147
+ });
148
+
149
+ program
150
+ .command('create <projectName>')
151
+ .description('创建新的项目')
152
+ .action((projectName) => {
153
+ // 检查git是否安装
154
+ if (!checkGit()) {
155
+ console.error('❌ 请先安装Git');
156
+ process.exit(1);
157
+ }
158
+
159
+ // 检查项目名是否已存在
160
+ if (fs.existsSync(projectName)) {
161
+ console.error('❌ 项目已存在');
162
+ process.exit(1);
163
+ }
164
+
165
+ // 获取远程仓库分支
166
+ const spinner = ora('正在获取模板列表...').start();
167
+ const branches = getRemoteBranches(TEMPLATE_REPO);
168
+ spinner.succeed('✅ 模板列表获取完成');
169
+
170
+ // 如果没有分支
171
+ if (branches.length === 0) {
172
+ console.error('❌ 仓库没有可用的分支');
173
+ process.exit(1);
174
+ }
175
+
176
+ // 选择模板(分支)
177
+ prompt([
178
+ {
179
+ type: 'checkbox',
180
+ name: 'branch',
181
+ message: '请选择项目模板 (空格选择,回车确认):',
182
+ choices: branches.map(branch => ({
183
+ name: branch,
184
+ value: branch
185
+ })),
186
+ validate: function(answer) {
187
+ if (answer.length !== 1) {
188
+ return '请选择一个模板';
189
+ }
190
+ return true;
191
+ }
192
+ },
193
+ { type: 'checkbox',
194
+ name: 'packageManager',
195
+ message: '请选择包管理器 (空格选择,回车确认):',
196
+ choices: ['npm', 'pnpm'],
197
+ validate: function(answer) {
198
+ if (answer.length !== 1) {
199
+ return '请选择一个包管理器';
200
+ }
201
+ return true;
202
+ }
203
+ }
204
+ ]).then(answers => {
205
+ // 检查包管理器是否安装
206
+ if (!checkPackageManager(answers.packageManager[0])) {
207
+ console.error(`❌ 请先安装 ${answers.packageManager[0]}`);
208
+ process.exit(1);
209
+ }
210
+
211
+ // 获取选中的分支(checkbox返回数组,取第一个元素)
212
+ const selectedBranch = answers.branch[0];
213
+ const branchSpinner = ora(`正在下载模板 (${selectedBranch})...`).start();
214
+
215
+ // 使用git命令直接克隆模板
216
+ try {
217
+ execSync(`git clone -b ${selectedBranch} ${TEMPLATE_REPO} ${projectName}`, {
218
+ stdio: 'inherit'
219
+ });
220
+ branchSpinner.succeed('✅ 模板下载完成');
221
+
222
+ // 安装依赖
223
+ const installSpinner = ora('正在安装依赖...').start();
224
+ try {
225
+ execSync(`${answers.packageManager[0]} install`, {
226
+ cwd: path.resolve(process.cwd(), projectName),
227
+ stdio: 'inherit'
228
+ });
229
+ installSpinner.succeed('✅ 依赖安装完成');
230
+
231
+ console.log('\n🎉 项目创建成功!');
232
+ console.log(`📁 项目目录: ${projectName}`);
233
+ console.log(`📦 包管理器: ${answers.packageManager[0]}`);
234
+ console.log(`\n接下来可以执行:`);
235
+ console.log(` cd ${projectName}`);
236
+ console.log(` ${answers.packageManager[0]} run dev\n`);
237
+ } catch (error) {
238
+ installSpinner.fail('❌ 依赖安装失败');
239
+ console.error('\n请尝试手动安装依赖:');
240
+ console.error(` cd ${projectName}`);
241
+ console.error(` ${answers.packageManager[0]} install\n`);
242
+ process.exit(1);
243
+ }
244
+ } catch (err) {
245
+ branchSpinner.fail('❌ 模板下载失败');
246
+ console.error('\n错误信息:', err.message);
247
+ console.error('\n请检查以下几点:');
248
+ console.error('1. 网络连接是否正常');
249
+ console.error('2. Git是否已正确安装');
250
+ console.error('3. 是否有权限访问该仓库');
251
+ process.exit(1);
252
+ }
253
+ });
254
+ });
255
+
256
+ // 配置命令
257
+ const configCommand = program.command('config');
258
+
259
+ // 设置配置
260
+ configCommand
261
+ .command('set <key> <value>')
262
+ .description('设置配置项')
263
+ .action((key, value) => {
264
+ if (setConfig(key, value)) {
265
+ console.log('✅ 配置设置成功');
266
+ }
267
+ });
268
+
269
+ // 获取配置
270
+ configCommand
271
+ .command('get <key>')
272
+ .description('获取配置项')
273
+ .action((key) => {
274
+ const value = getConfig(key);
275
+ if (value !== undefined) {
276
+ console.log(value);
277
+ } else {
278
+ console.log(`❌ 配置项 ${key} 不存在`);
279
+ }
280
+ });
281
+
282
+ // 删除配置
283
+ configCommand
284
+ .command('delete <key>')
285
+ .description('删除配置项')
286
+ .action((key) => {
287
+ const config = readConfig();
288
+ if (config[key] !== undefined) {
289
+ delete config[key];
290
+ if (writeConfig(config)) {
291
+ console.log('✅ 配置删除成功');
292
+ }
293
+ } else {
294
+ console.log(`❌ 配置项 ${key} 不存在`);
295
+ }
296
+ });
297
+
298
+ // 配置命令帮助
299
+ configCommand
300
+ .command('help')
301
+ .description('显示配置命令帮助')
302
+ .action(() => {
303
+ console.log('配置命令用法:');
304
+ console.log(' itbox config set <key> <value> 设置配置项');
305
+ console.log(' itbox config get <key> 获取配置项');
306
+ console.log(' itbox config delete <key> 删除配置项');
307
+ console.log(' itbox config help 显示帮助信息');
308
+ });
309
+
310
+ // 解析命令行参数
311
+ program.parse(process.argv);
312
+
313
+ // 如果没有传入命令,显示帮助信息
314
+ if (!process.argv.slice(2).length) {
315
+ program.outputHelp();
316
+ }
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@itbox/cli",
3
+ "version": "1.0.0",
4
+ "description": "前端项目模板生成工具,支持Vue、Vue+TypeScript、Nuxt、Nest等模板",
5
+ "type": "module",
6
+ "main": "bin/index.js",
7
+ "bin": {
8
+ "itbox": "bin/index.js",
9
+ "create-itbox": "bin/index.js"
10
+ },
11
+ "scripts": {
12
+ "test": "echo \"Error: no test specified\" && exit 1"
13
+ },
14
+ "keywords": [
15
+ "cli",
16
+ "vue",
17
+ "nuxt",
18
+ "nest",
19
+ "template"
20
+ ],
21
+ "author": "jianlidmeng",
22
+ "engines": {
23
+ "node": ">=14.0.0"
24
+ },
25
+ "files": [
26
+ "bin/",
27
+ "package.json"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "dependencies": {
33
+ "commander": "^14.0.2",
34
+ "fs-extra": "^11.3.3",
35
+ "inquirer": "^13.1.0",
36
+ "ora": "^9.0.0"
37
+ }
38
+ }