@xubill/xx-cli 2.0.0 → 2.0.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/AGENTS.md +177 -0
- package/lib/core/index.js +42 -9
- package/lib/plugins/ai.js +295 -0
- package/package.json +6 -1
- package/plugin-development-new.md +565 -0
- package/plugin-development-old.md +447 -0
- package/readme.md +54 -554
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
# 新格式插件开发教程
|
|
2
|
+
|
|
3
|
+
本教程将详细介绍如何在 xx-cli 中使用新格式(配置对象格式)创建、开发和部署插件,这是推荐的插件开发方式。
|
|
4
|
+
|
|
5
|
+
## 目录
|
|
6
|
+
|
|
7
|
+
- [新格式插件开发教程](#新格式插件开发教程)
|
|
8
|
+
- [目录](#目录)
|
|
9
|
+
- [创建插件](#创建插件)
|
|
10
|
+
- [使用 plugin create 命令](#使用-plugin-create-命令)
|
|
11
|
+
- [手动创建插件](#手动创建插件)
|
|
12
|
+
- [插件结构](#插件结构)
|
|
13
|
+
- [命令注册](#命令注册)
|
|
14
|
+
- [命令选项](#命令选项)
|
|
15
|
+
- [常用选项类型](#常用选项类型)
|
|
16
|
+
- [选项示例](#选项示例)
|
|
17
|
+
- [插件配置](#插件配置)
|
|
18
|
+
- [配置文件结构](#配置文件结构)
|
|
19
|
+
- [读取配置](#读取配置)
|
|
20
|
+
- [写入配置](#写入配置)
|
|
21
|
+
- [插件工具](#插件工具)
|
|
22
|
+
- [导入 plugins-helper](#导入-plugins-helper)
|
|
23
|
+
- [核心功能](#核心功能)
|
|
24
|
+
- [使用示例](#使用示例)
|
|
25
|
+
- [插件生命周期](#插件生命周期)
|
|
26
|
+
- [测试插件](#测试插件)
|
|
27
|
+
- [本地测试](#本地测试)
|
|
28
|
+
- [命令测试](#命令测试)
|
|
29
|
+
- [部署插件](#部署插件)
|
|
30
|
+
- [发布到插件目录](#发布到插件目录)
|
|
31
|
+
- [分享插件](#分享插件)
|
|
32
|
+
- [从外部添加插件](#从外部添加插件)
|
|
33
|
+
- [最佳实践](#最佳实践)
|
|
34
|
+
- [命名规范](#命名规范)
|
|
35
|
+
- [代码组织](#代码组织)
|
|
36
|
+
- [错误处理](#错误处理)
|
|
37
|
+
- [用户体验](#用户体验)
|
|
38
|
+
|
|
39
|
+
## 创建插件
|
|
40
|
+
|
|
41
|
+
### 使用 plugin create 命令
|
|
42
|
+
|
|
43
|
+
xx-cli 提供了 `plugin create` 命令,可以快速生成插件模板。这是推荐的创建插件的方式。
|
|
44
|
+
|
|
45
|
+
#### 基本用法
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# 创建插件到插件目录
|
|
49
|
+
xx plugin create <plugin-name>
|
|
50
|
+
|
|
51
|
+
# 或者使用别名
|
|
52
|
+
xx p create <plugin-name>
|
|
53
|
+
|
|
54
|
+
# 或者使用更短的别名
|
|
55
|
+
xx p cr <plugin-name>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### 示例
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# 创建一个名为 `hello-world` 的插件
|
|
62
|
+
xx plugin create hello-world
|
|
63
|
+
|
|
64
|
+
# 输出:
|
|
65
|
+
# 创建插件模板...
|
|
66
|
+
# 插件模板已成功创建到:/Users/xub/.xx-cli/plugins/hello-world.js
|
|
67
|
+
# 提示:请编辑插件文件,实现具体功能
|
|
68
|
+
# 测试方法:运行 "node bin/cli.js <插件命令>"
|
|
69
|
+
# 已自动打开 vscode 编辑插件文件
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 手动创建插件
|
|
73
|
+
|
|
74
|
+
如果需要更灵活地控制插件结构,也可以手动创建插件文件。
|
|
75
|
+
|
|
76
|
+
1. 在 `lib/plugins` 目录下创建一个新的 JavaScript 文件,例如 `my-plugin.js`
|
|
77
|
+
2. 实现插件类,包含必要的方法
|
|
78
|
+
|
|
79
|
+
## 插件结构
|
|
80
|
+
|
|
81
|
+
新格式使用配置对象定义插件,结合了配置对象的简洁性和类结构的模块化优势,是推荐的插件开发方式。
|
|
82
|
+
|
|
83
|
+
使用 `plugin create` 命令生成的默认插件模板包含以下结构:
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
/**
|
|
87
|
+
* hello-world 插件
|
|
88
|
+
* 用于实现 hello-world 相关功能
|
|
89
|
+
*
|
|
90
|
+
* 命令说明:
|
|
91
|
+
* - helloWorld [options]:hello-world 相关功能
|
|
92
|
+
* - 示例:helloWorld
|
|
93
|
+
*
|
|
94
|
+
* 功能说明:
|
|
95
|
+
* - 实现 hello-world 相关功能
|
|
96
|
+
*
|
|
97
|
+
* 用户体验:
|
|
98
|
+
* - 使用标准化的用户提示
|
|
99
|
+
* - 提供清晰的错误提示
|
|
100
|
+
* - 支持命令行参数
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* hello-world 插件类
|
|
105
|
+
* 实现 hello-world 相关核心功能
|
|
106
|
+
*/
|
|
107
|
+
class HelloWorldPlugin {
|
|
108
|
+
constructor() {
|
|
109
|
+
this.pluginName = 'hello-world';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 执行 hello-world 命令
|
|
114
|
+
* @param {Array} args - 命令参数
|
|
115
|
+
* @param {Object} options - 命令选项
|
|
116
|
+
* @param {Object} helper - 插件帮助器
|
|
117
|
+
*/
|
|
118
|
+
async execute(args, options, helper) {
|
|
119
|
+
helper.showInfo('hello-world 命令执行成功!');
|
|
120
|
+
if (options && options.verbose) {
|
|
121
|
+
helper.showInfo('详细信息:');
|
|
122
|
+
helper.showInfo('- 命令名称: helloWorld');
|
|
123
|
+
helper.showInfo('- 执行时间: ' + new Date().toLocaleString());
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 创建插件实例
|
|
129
|
+
const pluginInstance = new HelloWorldPlugin();
|
|
130
|
+
|
|
131
|
+
module.exports = {
|
|
132
|
+
name: "helloWorld",
|
|
133
|
+
alias: "h",
|
|
134
|
+
description: "hello-world 相关功能",
|
|
135
|
+
options: [
|
|
136
|
+
{
|
|
137
|
+
name: "-v, --verbose",
|
|
138
|
+
description: "显示详细信息",
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: "-h, --help",
|
|
142
|
+
description: "显示帮助信息",
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
action: async (args, options, helper) => {
|
|
146
|
+
await pluginInstance.execute(args, options, helper);
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 命令注册
|
|
152
|
+
|
|
153
|
+
对于新格式的插件,命令注册通过配置对象的 `options` 和 `action` 属性实现:
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
module.exports = {
|
|
157
|
+
name: 'helloWorld',
|
|
158
|
+
alias: 'hw',
|
|
159
|
+
description: 'hello-world 相关功能',
|
|
160
|
+
options: [
|
|
161
|
+
{
|
|
162
|
+
name: '-v, --verbose',
|
|
163
|
+
description: '显示详细信息'
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
name: '-n, --name <name>',
|
|
167
|
+
description: '指定名称'
|
|
168
|
+
}
|
|
169
|
+
],
|
|
170
|
+
action: async (args, options, helper) => {
|
|
171
|
+
await pluginInstance.execute(args, options, helper);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## 命令选项
|
|
177
|
+
|
|
178
|
+
命令选项可以增强命令的灵活性,允许用户自定义命令行为。
|
|
179
|
+
|
|
180
|
+
### 常用选项类型
|
|
181
|
+
|
|
182
|
+
#### 1. 布尔选项
|
|
183
|
+
|
|
184
|
+
不需要参数的选项,用于开关功能。
|
|
185
|
+
|
|
186
|
+
```javascript
|
|
187
|
+
options: [
|
|
188
|
+
{
|
|
189
|
+
name: '-v, --verbose',
|
|
190
|
+
description: '显示详细信息'
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### 2. 值选项
|
|
196
|
+
|
|
197
|
+
需要参数的选项,用于传递具体值。
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
options: [
|
|
201
|
+
{
|
|
202
|
+
name: '-n, --name <name>',
|
|
203
|
+
description: '指定名称'
|
|
204
|
+
}
|
|
205
|
+
]
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### 3. 数组选项
|
|
209
|
+
|
|
210
|
+
可以接收多个值的选项。
|
|
211
|
+
|
|
212
|
+
```javascript
|
|
213
|
+
options: [
|
|
214
|
+
{
|
|
215
|
+
name: '-a, --array <items...>',
|
|
216
|
+
description: '指定数组参数'
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### 4. 带默认值的选项
|
|
222
|
+
|
|
223
|
+
设置选项的默认值。
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
options: [
|
|
227
|
+
{
|
|
228
|
+
name: '-p, --port <port>',
|
|
229
|
+
description: '指定端口',
|
|
230
|
+
default: '3000'
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
#### 5. 带验证器的选项
|
|
236
|
+
|
|
237
|
+
使用验证器处理选项值。
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
options: [
|
|
241
|
+
{
|
|
242
|
+
name: '-p, --port <port>',
|
|
243
|
+
description: '指定端口',
|
|
244
|
+
validator: parseInt
|
|
245
|
+
}
|
|
246
|
+
]
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### 选项示例
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
module.exports = {
|
|
253
|
+
name: 'example',
|
|
254
|
+
description: '示例命令',
|
|
255
|
+
options: [
|
|
256
|
+
{
|
|
257
|
+
name: '-v, --verbose',
|
|
258
|
+
description: '显示详细信息'
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
name: '-n, --name <name>',
|
|
262
|
+
description: '指定名称'
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
name: '-a, --array <items...>',
|
|
266
|
+
description: '指定数组参数'
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
name: '-p, --port <port>',
|
|
270
|
+
description: '指定端口',
|
|
271
|
+
default: '3000'
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
name: '-c, --count <count>',
|
|
275
|
+
description: '指定数量',
|
|
276
|
+
validator: parseInt
|
|
277
|
+
}
|
|
278
|
+
],
|
|
279
|
+
action: async (args, options, helper) => {
|
|
280
|
+
helper.showInfo('示例命令执行成功!');
|
|
281
|
+
if (options.verbose) {
|
|
282
|
+
helper.showInfo('详细信息:');
|
|
283
|
+
helper.showInfo(`- 名称: ${options.name || '未指定'}`);
|
|
284
|
+
helper.showInfo(`- 数组: ${options.array ? options.array.join(', ') : '未指定'}`);
|
|
285
|
+
helper.showInfo(`- 端口: ${options.port}`);
|
|
286
|
+
helper.showInfo(`- 数量: ${options.count || '未指定'}`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## 插件配置
|
|
293
|
+
|
|
294
|
+
插件可以使用配置文件来存储和管理配置信息,例如默认值、用户偏好设置等。
|
|
295
|
+
|
|
296
|
+
### 配置文件结构
|
|
297
|
+
|
|
298
|
+
配置文件通常存储在用户主目录的 `.xx-cli` 文件夹中,例如:
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
~/.xx-cli/
|
|
302
|
+
└── hello-world/
|
|
303
|
+
└── config.json
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### 读取配置
|
|
307
|
+
|
|
308
|
+
```javascript
|
|
309
|
+
const fs = require('fs-extra');
|
|
310
|
+
const path = require('path');
|
|
311
|
+
|
|
312
|
+
// 获取用户主目录
|
|
313
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
314
|
+
const xxDir = path.join(homeDir, '.xx-cli');
|
|
315
|
+
const pluginConfigDir = path.join(xxDir, 'hello-world');
|
|
316
|
+
const configFile = path.join(pluginConfigDir, 'config.json');
|
|
317
|
+
|
|
318
|
+
// 读取配置
|
|
319
|
+
let config = {};
|
|
320
|
+
if (fs.existsSync(configFile)) {
|
|
321
|
+
config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### 写入配置
|
|
326
|
+
|
|
327
|
+
```javascript
|
|
328
|
+
const fs = require('fs-extra');
|
|
329
|
+
const path = require('path');
|
|
330
|
+
|
|
331
|
+
// 获取用户主目录
|
|
332
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
333
|
+
const xxDir = path.join(homeDir, '.xx-cli');
|
|
334
|
+
const pluginConfigDir = path.join(xxDir, 'hello-world');
|
|
335
|
+
const configFile = path.join(pluginConfigDir, 'config.json');
|
|
336
|
+
|
|
337
|
+
// 确保配置目录存在
|
|
338
|
+
fs.ensureDirSync(pluginConfigDir);
|
|
339
|
+
|
|
340
|
+
// 写入配置
|
|
341
|
+
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## 插件工具
|
|
345
|
+
|
|
346
|
+
对于新格式的插件,使用 `plugins-helper` 提供的功能来替代 `BasePlugin` 类的方法:
|
|
347
|
+
|
|
348
|
+
### 导入 plugins-helper
|
|
349
|
+
|
|
350
|
+
```javascript
|
|
351
|
+
const { createPluginsHelper } = require('../utils/plugins-helper');
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### 核心功能
|
|
355
|
+
|
|
356
|
+
`plugins-helper` 提供了以下核心功能:
|
|
357
|
+
|
|
358
|
+
#### 1. 用户界面
|
|
359
|
+
|
|
360
|
+
- **`helper.showInfo(text)`**:显示信息
|
|
361
|
+
- **`helper.showSuccess(text)`**:显示成功信息
|
|
362
|
+
- **`helper.showWarning(text)`**:显示警告信息
|
|
363
|
+
- **`helper.showError(text)`**:显示错误信息
|
|
364
|
+
- **`helper.startLoading(text)`**:显示加载状态
|
|
365
|
+
- **`helper.stopLoading(text)`**:停止加载状态
|
|
366
|
+
|
|
367
|
+
#### 2. 配置管理
|
|
368
|
+
|
|
369
|
+
可以使用 `fs-extra` 和 `path` 模块来实现配置管理:
|
|
370
|
+
|
|
371
|
+
```javascript
|
|
372
|
+
const fs = require('fs-extra');
|
|
373
|
+
const path = require('path');
|
|
374
|
+
|
|
375
|
+
// 确保配置目录存在
|
|
376
|
+
function ensureConfigDir(pluginName) {
|
|
377
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
378
|
+
const xxDir = path.join(homeDir, '.xx-cli');
|
|
379
|
+
const pluginConfigDir = path.join(xxDir, pluginName);
|
|
380
|
+
fs.ensureDirSync(pluginConfigDir);
|
|
381
|
+
return pluginConfigDir;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// 加载配置
|
|
385
|
+
function loadConfig(pluginName) {
|
|
386
|
+
const configDir = ensureConfigDir(pluginName);
|
|
387
|
+
const configFile = path.join(configDir, 'config.json');
|
|
388
|
+
if (fs.existsSync(configFile)) {
|
|
389
|
+
return JSON.parse(fs.readFileSync(configFile, 'utf8'));
|
|
390
|
+
}
|
|
391
|
+
return {};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// 保存配置
|
|
395
|
+
function saveConfig(pluginName, config) {
|
|
396
|
+
const configDir = ensureConfigDir(pluginName);
|
|
397
|
+
const configFile = path.join(configDir, 'config.json');
|
|
398
|
+
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### 使用示例
|
|
403
|
+
|
|
404
|
+
```javascript
|
|
405
|
+
const { createPluginsHelper } = require('../utils/plugins-helper');
|
|
406
|
+
|
|
407
|
+
class MyPlugin {
|
|
408
|
+
constructor() {
|
|
409
|
+
this.pluginName = 'my-plugin';
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
async execute(args, options, helper) {
|
|
413
|
+
try {
|
|
414
|
+
helper.showInfo('执行操作...');
|
|
415
|
+
|
|
416
|
+
// 执行操作
|
|
417
|
+
setTimeout(() => {
|
|
418
|
+
helper.showSuccess('操作成功');
|
|
419
|
+
|
|
420
|
+
if (options && options.verbose) {
|
|
421
|
+
helper.showInfo('详细信息:');
|
|
422
|
+
helper.showInfo('- 执行时间:', new Date().toLocaleString());
|
|
423
|
+
}
|
|
424
|
+
}, 1000);
|
|
425
|
+
} catch (error) {
|
|
426
|
+
helper.showError(`执行命令失败: ${error.message}`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// 创建插件实例
|
|
432
|
+
const pluginInstance = new MyPlugin();
|
|
433
|
+
|
|
434
|
+
module.exports = {
|
|
435
|
+
name: 'myPlugin',
|
|
436
|
+
description: 'My plugin command',
|
|
437
|
+
options: [
|
|
438
|
+
{
|
|
439
|
+
name: '-v, --verbose',
|
|
440
|
+
description: '显示详细信息'
|
|
441
|
+
}
|
|
442
|
+
],
|
|
443
|
+
action: (args, options, helper) => {
|
|
444
|
+
pluginInstance.execute(args, options, helper);
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
## 插件生命周期
|
|
450
|
+
|
|
451
|
+
插件的生命周期包括以下阶段:
|
|
452
|
+
|
|
453
|
+
1. **初始化**:插件被加载时,系统会创建插件实例并准备执行环境
|
|
454
|
+
2. **命令注册**:系统会自动解析配置对象并注册命令
|
|
455
|
+
3. **命令执行**:用户运行插件命令时,系统会调用相应的 `action` 函数
|
|
456
|
+
4. **清理**:命令执行完成后,系统会清理临时资源
|
|
457
|
+
|
|
458
|
+
## 测试插件
|
|
459
|
+
|
|
460
|
+
### 本地测试
|
|
461
|
+
|
|
462
|
+
#### 1. 创建插件
|
|
463
|
+
|
|
464
|
+
```bash
|
|
465
|
+
xx plugin create <plugin-name>
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
#### 2. 编辑插件文件,实现具体功能
|
|
469
|
+
|
|
470
|
+
#### 3. 运行插件命令
|
|
471
|
+
|
|
472
|
+
```bash
|
|
473
|
+
# 直接运行
|
|
474
|
+
node bin/cli.js <plugin-command>
|
|
475
|
+
|
|
476
|
+
# 或者使用 xx 命令(如果已全局安装)
|
|
477
|
+
xx <plugin-command>
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### 命令测试
|
|
481
|
+
|
|
482
|
+
测试命令选项和参数:
|
|
483
|
+
|
|
484
|
+
```bash
|
|
485
|
+
# 测试布尔选项
|
|
486
|
+
xx <plugin-command> --verbose
|
|
487
|
+
|
|
488
|
+
# 测试值选项
|
|
489
|
+
xx <plugin-command> --name John
|
|
490
|
+
|
|
491
|
+
# 测试组合选项
|
|
492
|
+
xx <plugin-command> --verbose --name John
|
|
493
|
+
|
|
494
|
+
# 测试数组选项
|
|
495
|
+
xx <plugin-command> --array item1 item2 item3
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
## 部署插件
|
|
499
|
+
|
|
500
|
+
### 发布到插件目录
|
|
501
|
+
|
|
502
|
+
1. 确保插件文件位于 `lib/plugins` 或 `lib/myplugins` 目录
|
|
503
|
+
2. 运行 `xx plugin list` 命令,确认插件已被识别
|
|
504
|
+
3. 插件会自动加载并注册到命令系统中
|
|
505
|
+
|
|
506
|
+
### 分享插件
|
|
507
|
+
|
|
508
|
+
如果要与他人分享插件,可以:
|
|
509
|
+
|
|
510
|
+
1. 将插件文件发送给他人
|
|
511
|
+
2. 他人将插件文件放入其 `lib/plugins` 或 `lib/myplugins` 目录
|
|
512
|
+
3. 运行 `xx plugin list` 命令,确认插件已被识别
|
|
513
|
+
|
|
514
|
+
### 从外部添加插件
|
|
515
|
+
|
|
516
|
+
可以使用 `plugin add` 命令从 URL 或本地文件添加插件:
|
|
517
|
+
|
|
518
|
+
```bash
|
|
519
|
+
# 从 URL 添加插件
|
|
520
|
+
xx plugin add https://example.com/my-plugin.js
|
|
521
|
+
|
|
522
|
+
# 从本地文件添加插件
|
|
523
|
+
xx plugin add /path/to/my-plugin.js
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
## 最佳实践
|
|
527
|
+
|
|
528
|
+
### 命名规范
|
|
529
|
+
|
|
530
|
+
1. **插件名称**:使用小写字母和连字符,例如 `hello-world`
|
|
531
|
+
2. **命令名称**:使用驼峰命名法,例如 `helloWorld`
|
|
532
|
+
3. **选项名称**:使用小写字母和连字符,例如 `--verbose`
|
|
533
|
+
4. **变量名称**:使用驼峰命名法,例如 `pluginName`
|
|
534
|
+
|
|
535
|
+
### 代码组织
|
|
536
|
+
|
|
537
|
+
1. **模块化**:将不同功能的代码分离到不同的方法中
|
|
538
|
+
2. **注释**:为关键代码添加注释,解释功能和实现细节
|
|
539
|
+
3. **错误处理**:使用 try-catch 捕获和处理错误
|
|
540
|
+
4. **日志**:使用 helper 提供的方法输出日志信息
|
|
541
|
+
|
|
542
|
+
### 错误处理
|
|
543
|
+
|
|
544
|
+
1. **捕获错误**:使用 try-catch 捕获可能的错误
|
|
545
|
+
2. **错误提示**:使用 `helper.showError` 显示友好的错误信息
|
|
546
|
+
3. **错误传递**:对于无法处理的错误,应该向上传递
|
|
547
|
+
|
|
548
|
+
### 用户体验
|
|
549
|
+
|
|
550
|
+
1. **加载状态**:对于耗时操作,使用 `helper.startLoading` 显示加载状态
|
|
551
|
+
2. **成功提示**:操作成功后,使用 `helper.showSuccess` 显示成功信息
|
|
552
|
+
3. **信息提示**:使用 `helper.showInfo` 显示有用的信息
|
|
553
|
+
4. **警告提示**:使用 `helper.showWarning` 显示警告信息
|
|
554
|
+
|
|
555
|
+
### 性能优化
|
|
556
|
+
|
|
557
|
+
1. **异步操作**:对于耗时操作,使用异步方法
|
|
558
|
+
2. **缓存**:对于重复计算的结果,使用缓存
|
|
559
|
+
3. **惰性加载**:对于不常用的功能,使用惰性加载
|
|
560
|
+
|
|
561
|
+
### 安全性
|
|
562
|
+
|
|
563
|
+
1. **输入验证**:验证用户输入,防止恶意输入
|
|
564
|
+
2. **文件操作**:安全处理文件操作,防止路径遍历攻击
|
|
565
|
+
3. **网络请求**:安全处理网络请求,防止 XSS 攻击
|