创建一个 Discord 机器人
Discord.js 可直接运行在 Bun 上,无需额外配置。本指南将构建一个响应 /ping 斜杠命令的机器人:你只需注册一次命令,然后启动机器人并在你的服务器中使用它。如果这是你第一次创建机器人,建议在读到每个代码块时就直接复制。
为你的机器人创建一个文件夹,并使用 bun init 进行初始化。出现提示时选择默认选项。
mkdir my-bot
cd my-bot
bun init
将 Discord.js 添加到项目中。
bun add discord.js
你的机器人需要自己的账号,你可以在 Discord 的开发者门户中创建该账号。打开 developer portal,登录并创建一个 Application。Discord 会自动为每个新应用添加一个机器人用户;你可以在 Bot 选项卡中找到它。如果你遇到困难,Discord.js 指南中的设置教程提供了截图。
从门户中复制两个值:
- Bot 选项卡中的 token:点击 Reset Token 生成它(Discord 只会显示一次)。它是你的代码用于登录的密码,因此请像对待密码一样保护它,不要向他人透露
- General Information 选项卡中的 Application ID。Discord 使用它将你的命令关联到此应用
在你邀请机器人之前,它无法在服务器中执行任何操作。在门户的 OAuth2 部分,生成一个包含 bot 和 applications.commands 范围的邀请 URL,打开该 URL,然后将机器人添加到你管理的服务器中。斜杠命令需要 applications.commands 范围,因此请务必包含它。你可以先在自己创建的个人测试服务器中进行测试;Discord.js 的添加机器人指南提供了带截图的操作步骤。
你还需要服务器的 ID,才能在该服务器中注册命令。在 Discord 中,打开 Settings > Advanced > Developer Mode,然后右键单击服务器图标并选择 Copy Server ID。
将这三个值保存到 .env.local 中。Bun 会在启动时读取这个文件并将其加载到 process.env,因此你的代码里不会出现任何密钥。
DISCORD_TOKEN=your-bot-token
DISCORD_CLIENT_ID=your-application-id
DISCORD_GUILD_ID=your-server-id
在提交任何内容之前,将 .env.local 添加到 .gitignore。任何读取到令牌的人都可以控制你的机器人,因此绝不能将令牌提交到版本控制中。
node_modules
.env.local
在任何人能使用命令之前,Discord 必须先知道这个命令。使用一个名为 deploy-commands.ts 的简短脚本注册 /ping。
import { REST, Routes, SlashCommandBuilder } from "discord.js";
const { DISCORD_TOKEN, DISCORD_CLIENT_ID, DISCORD_GUILD_ID } = process.env;
if (!DISCORD_TOKEN || !DISCORD_CLIENT_ID || !DISCORD_GUILD_ID) {
throw new Error("在 .env.local 中设置 DISCORD_TOKEN、DISCORD_CLIENT_ID 和 DISCORD_GUILD_ID");
}
// 你想要注册的命令
const commands = [new SlashCommandBuilder().setName("ping").setDescription("回复 Pong!").toJSON()];
const rest = new REST().setToken(DISCORD_TOKEN);
// 在你的测试服务器中注册它们
await rest.put(Routes.applicationGuildCommands(DISCORD_CLIENT_ID, DISCORD_GUILD_ID), { body: commands });
console.log("已注册 /ping");
运行一次即可。
bun run deploy-commands.ts
只有在你添加命令,或者更改命令名称或描述时,才需要再次运行它,而不是每次机器人启动时都运行。注册到你的服务器而不是全局注册,可以让命令只在你的测试范围内可用。
接下来是机器人本体。将其保存为 bot.ts。
import { Client, Events, GatewayIntentBits } from "discord.js";
const { DISCORD_TOKEN } = process.env;
if (!DISCORD_TOKEN) {
throw new Error("在 .env.local 中设置 DISCORD_TOKEN");
}
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
// 在机器人连接后立即运行一次
client.once(Events.ClientReady, readyClient => {
console.log(`Logged in as ${readyClient.user.tag}`);
});
// 每次有人使用斜杠命令时运行
client.on(Events.InteractionCreate, async interaction => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === "ping") {
await interaction.reply("Pong!");
}
});
client.login(DISCORD_TOKEN);
ready 处理器会在机器人连接后输出一行日志。之后,只要有人使用斜杠命令,interactionCreate 就会运行;它会确认命令是否为 /ping,并回复 Pong!。
使用 bun run 启动机器人。
bun run bot.ts
首次连接需要几秒钟。等登录信息打印出来后,切换到 Discord,在你的服务器中输入 /ping。
Logged in as my-bot#1234
机器人会回复 Pong!。你已经拥有一个可工作的 Discord 机器人了。
要添加另一个命令,只需在 deploy-commands.ts 中定义它,再运行一次脚本,并在 bot.ts 中为它的名称添加一个 if 分支。Discord.js 文档涵盖了命令选项、权限、按钮、嵌入消息以及 API 的其余部分。
部署时,不需要构建或打包步骤。Bun 会直接运行 bot.ts 及其导入的每个文件,因此你可以原样部署源码,并使用开发时相同的 bun run bot.ts 启动它。
deploy-commands.ts 会在你的测试服务器中注册 /ping,这在开发阶段是正确的作用范围。若要将机器人发布到它加入的每个服务器中,请改为全局注册:将路由改为 Routes.applicationCommands(DISCORD_CLIENT_ID)。全局注册不需要服务器,因此你也可以从脚本的检查和 .env.local 中移除 DISCORD_GUILD_ID。
为了让机器人保持在线,并在崩溃或重启后恢复运行,请在进程管理器下运行它。