跳到主要内容

多文件模块化开发

当你的插件变得复杂时,将所有代码写在一个 main.js 文件中会变得难以维护。EasyBot 支持使用 ES 模块的相对路径导入其他 JavaScript 文件,让你可以将代码分割成多个模块。

项目结构

一个典型的多文件插件项目结构如下:

my_plugin/
├── manifest.json
├── main.js
├── utils/
│ ├── helper.js
│ └── config.js
└── handlers/
├── commands.js
└── events.js

创建工具模块

首先,让我们创建一个工具模块。在插件目录下创建 utils 文件夹,然后创建 helper.js 文件:

utils/helper.js
// 工具函数模块

/**
* 格式化时间
* @param {Date} date
* @returns {string}
*/
export function formatTime(date = new Date()) {
return date.toLocaleString('zh-CN');
}

/**
* 生成随机数
* @param {number} min
* @param {number} max
* @returns {number}
*/
export function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}

/**
* 获取当前时间戳
* @returns {number}
*/
export function getTimestamp() {
return Date.now();
}

创建配置模块

创建 utils/config.js 文件来管理插件配置:

utils/config.js
// 配置管理模块

const config = {
pluginName: "多文件示例插件",
version: "1.0.0",
maxRetries: 3,
timeout: 5000
};

/**
* 获取配置值
* @param {string} key
* @returns {any}
*/
export function getConfig(key) {
return config[key];
}

/**
* 设置配置值
* @param {string} key
* @param {any} value
*/
export function setConfig(key, value) {
config[key] = value;
}

/**
* 获取所有配置
* @returns {object}
*/
export function getAllConfig() {
return { ...config };
}

// 默认导出配置对象
export default config;

创建命令处理模块

创建 handlers/commands.js 文件来处理命令:

handlers/commands.js
// 命令处理模块
import { formatTime, randomInt } from '../utils/helper.js';
import { getConfig } from '../utils/config.js';

/**
* 处理时间命令
*/
export function handleTimeCommand() {
const currentTime = formatTime();
logger.info(`当前时间: ${currentTime}`);
return currentTime;
}

/**
* 处理随机数命令
* @param {number} min
* @param {number} max
*/
export function handleRandomCommand(min = 1, max = 100) {
const result = randomInt(min, max);
logger.info(`随机数 (${min}-${max}): ${result}`);
return result;
}

/**
* 处理插件信息命令
*/
export function handleInfoCommand() {
const name = getConfig('pluginName');
const version = getConfig('version');
logger.info(`插件信息: ${name} v${version}`);
return { name, version };
}

/**
* 处理帮助命令
*/
export function handleHelpCommand() {
const commands = ['time', 'random', 'info', 'help'];
logger.info(`可用命令: ${commands.join(', ')}`);
return commands;
}

创建事件处理模块

创建 handlers/events.js 文件来处理事件:

handlers/events.js
// 事件处理模块
import { formatTime } from '../utils/helper.js';

/**
* 注册所有事件监听器
*/
export function registerEvents() {
// 插件启用事件
bus.on('enable', () => {
const time = formatTime();
logger.info(`[${time}] 多文件插件已启用`);
});

// 插件禁用事件
bus.on('disable', () => {
const time = formatTime();
logger.info(`[${time}] 多文件插件已禁用`);
});

// 服务器连接事件
bus.on('bridge.connected', (data) => {
const time = formatTime();
logger.info(`[${time}] 服务器已连接: ${data.serverName}`);
});
}

/**
* 注册机器人事件
*/
export function registerRobotEvents() {
bus.on('robot.message', (data) => {
const time = formatTime();
logger.info(`[${time}] 收到消息: ${data.message}`);
});
}

主入口文件

现在修改 main.js 文件,导入并使用这些模块:

main.js
/// <reference path="easybot-sdk/easybot.d.ts" />

// 导入模块
import { handleTimeCommand, handleRandomCommand, handleInfoCommand } from './handlers/commands.js';
import { registerEvents } from './handlers/events.js';
import { setConfig } from './utils/config.js';

logger.info("多文件插件被加载");

// 初始化配置
setConfig('pluginName', '我的多文件插件');

// 注册事件
registerEvents();

// 示例:定时执行命令
setTimeout(() => {
handleTimeCommand();
handleRandomCommand(1, 10);
handleInfoCommand();
}, 2000);

ES 模块导入规则

在 EasyBot 插件中使用 ES 模块时,需要注意以下规则:

基本语法

// 命名导入
import { function1, function2 } from './filename.js';

// 默认导入
import defaultExport from './filename.js';

// 混合导入
import defaultExport, { namedExport } from './filename.js';

// 导入所有
import * as moduleName from './filename.js';

路径示例

// 当前文件: handlers/commands.js
import { formatTime } from '../utils/helper.js'; // 正确
import { getConfig } from '../utils/config.js'; // 正确
import mainModule from '../main.js'; // 正确

// 当前文件: main.js
import { handleTimeCommand } from './handlers/commands.js'; // 正确
import { registerEvents } from './handlers/events.js'; // 正确

更新插件清单

更新 manifest.json 文件:

manifest.json
{
"name": "多文件示例插件",
"version": "1.0.0",
"plugin_id": "multi_file_example",
"author": "MiuxuE",
"description": "演示如何使用多文件模块化开发EasyBot插件",
"tags": ["示例", "模块化"],
"entry": "main.js",
"contents": "# 多文件模块化插件\n\n这个插件演示了如何使用多个JavaScript文件来组织代码,提高代码的可维护性。"
}

测试插件

重启 EasyBot 后,你应该能看到类似以下的输出:

[2024-01-01 12:00:00] 多文件插件被加载
[2024-01-01 12:00:00] [2024-01-01 12:00:00] 多文件插件已启用
[2024-01-01 12:00:02] 当前时间: 2024-01-01 12:00:02
[2024-01-01 12:00:02] 随机数 (1-10): 7
[2024-01-01 12:00:02] 插件信息: 我的多文件插件 v1.0.0

最佳实践

1. 目录结构建议

plugin/
├── manifest.json
├── main.js # 主入口文件
├── utils/ # 工具函数
│ ├── helper.js
│ └── config.js
├── handlers/ # 事件和命令处理
│ ├── commands.js
│ └── events.js
├── models/ # 数据模型
│ └── player.js
└── services/ # 业务逻辑
└── database.js

2. ES 模块导出规范

// 命名导出(推荐)
export function myFunction() { }
export const myConstant = 'value';

// 默认导出
export default class MyClass { }

// 混合导出
export function helper() { }
export default config;

3. 导入最佳实践

// 只导入需要的函数
import { formatTime, randomInt } from './utils/helper.js';

// 使用别名避免命名冲突
import { getConfig as getPluginConfig } from './utils/config.js';

// 导入默认导出
import config from './utils/config.js';

4. 避免循环依赖

// 错误示例:A.js 和 B.js 互相引用
// A.js
import { functionB } from './B.js';

// B.js
import { functionA } from './A.js'; // 循环依赖!
提示

合理的模块化可以让你的插件代码更加清晰、易于维护和测试。建议按功能将代码分割到不同的文件中。

注意
  • 文件路径必须使用 .js 扩展名
  • 相对路径以当前文件为基准
  • 使用 ES 模块语法(import/export)
  • 避免循环依赖
  • 所有模块文件都需要包含在插件包中