> ## Documentation Index
> Fetch the complete documentation index at: https://bun.ll1025.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 创建 Discord 机器人

Discord.js 在 Bun 上无需额外配置即可运行。本指南构建一个回答 `/ping` 斜杠命令的机器人：你注册一次命令，然后启动机器人在你的服务器中使用。如果这是你的第一个机器人，请按顺序复制每个代码块。

***

为你的机器人创建一个文件夹并用 `bun init` 进行设置。当它询问时选择默认选项。

```sh terminal icon="terminal" theme={null}
mkdir my-bot
cd my-bot
bun init
```

***

将 Discord.js 添加到项目。

```sh terminal icon="terminal" theme={null}
bun add discord.js
```

***

你的机器人需要自己的账户，你在 Discord 的开发者门户中创建。打开[开发者门户](https://discord.com/developers/applications)，登录并创建一个**应用**。在其中，打开 **Bot** 标签页以创建机器人用户。如果遇到问题，Discord 的[设置指南](https://discordjs.guide/legacy/preparations/app-setup)有截图帮助。

从门户复制两个值：

* **Bot** 标签页上的 **token**。这是你的代码用来登录的密码，所以请像对待密码一样保管好它，不要泄露。
* **General Information** 标签页上的 **Application ID**。Discord 用它来将你的命令与此应用关联。

***

一个机器人只有在被邀请后才能在你的服务器中做任何事。在门户的 **OAuth2** 部分，生成一个带有 `bot` 和 `applications.commands` 作用域的邀请 URL，打开它，并将机器人添加到你管理的服务器中。斜杠命令需要 `applications.commands` 作用域，所以不要跳过它。一个你创建的用于测试的个人服务器是最简单的开始方式，Discord 的[添加机器人指南](https://discordjs.guide/legacy/preparations/adding-your-app)有截图指导。

***

你还需要你的服务器 ID 来注册命令。在 Discord 中，打开 **设置 > 高级 > 开发者模式**，然后右键点击你的服务器图标并选择 **复制服务器 ID**。

***

将所有三个值保存在 `.env.local` 中。Bun 在启动时读取此文件并将其加载到 `process.env` 中，因此任何秘密都不会出现在你的代码中。

```ini .env.local icon="settings" theme={null}
DISCORD_TOKEN=你的机器人令牌
DISCORD_CLIENT_ID=你的应用 ID
DISCORD_GUILD_ID=你的服务器 ID
```

***

在提交任何内容之前，将 `.env.local` 添加到你的 `.gitignore`。任何读到 token 的人都可以控制你的机器人，所以它永远不应该进入版本控制。

```txt .gitignore icon="file-code" theme={null}
node_modules
.env.local
```

***

Discord 必须知道一个命令之后，其他人才能使用它。使用一个名为 `deploy-commands.ts` 的简短脚本注册 `/ping`。

```ts deploy-commands.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
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");
```

运行一次。

```sh terminal icon="terminal" theme={null}
bun run deploy-commands.ts
```

你只需要在添加命令或更改其名称或描述时再次运行此脚本，而不是每次机器人启动时。注册到你的服务器而不是全局范围，可以将命令限制在你测试的地方。

***

现在机器人本身。将其保存为 `bot.ts`。

```ts bot.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
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(`已登录为 ${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` 启动机器人。

```sh terminal icon="terminal" theme={null}
bun run bot.ts
```

第一次连接需要几秒钟。一旦登录行打印出来，切换到 Discord 并在你的服务器中输入 `/ping`。

```txt theme={null}
已登录为 my-bot#1234
```

机器人回复 `Pong！`。你已经有了一个可以工作的 Discord 机器人。

***

要添加另一个命令，在 `deploy-commands.ts` 中定义它，再次运行该脚本，并在 `bot.ts` 中为其名称添加一个 `if` 分支。[Discord.js 文档](https://discord.js.org/docs)涵盖了命令选项、权限、按钮、嵌入和其余 API。

***

当你部署时，没有构建或打包步骤。Bun 直接运行 `bot.ts` 及其导入的每个文件，因此你可以原样交付源代码，并使用与开发时相同的 `bun run bot.ts` 启动它。

`deploy-commands.ts` 在你的测试服务器中注册 `/ping`，这在构建期间是合适的作用域。要将机器人发布到它加入的每个服务器，改为全局注册：将路由更改为 `Routes.applicationCommands(DISCORD_CLIENT_ID)`。全局注册不使用服务器，因此你也可以从脚本检查和 `.env.local` 中删除 `DISCORD_GUILD_ID`。

要让机器人保持在线并在崩溃或重启后恢复运行，可以在进程管理器下运行它。

<Columns cols={2}>
  <Card title="systemd" href="/guides/ecosystem/systemd" icon="server">
    将你的机器人作为 Linux 守护进程运行
  </Card>

  <Card title="PM2" href="/guides/ecosystem/pm2" icon="cog">
    使用 PM2 管理你的机器人
  </Card>
</Columns>
