mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-13 10:03:31 +01:00
refactor(guide): next 13
This commit is contained in:
249
apps/guide/src/content/additional-info/async-await.mdx
Normal file
249
apps/guide/src/content/additional-info/async-await.mdx
Normal file
@@ -0,0 +1,249 @@
|
||||
---
|
||||
title: Understanding async/await
|
||||
category: Additional info
|
||||
---
|
||||
|
||||
# Understanding async/await
|
||||
|
||||
If you aren't very familiar with ECMAScript 2017, you may not know about async/await. It's a useful way to handle Promises in a hoisted manner. It's also slightly faster and increases overall readability.
|
||||
|
||||
## How do Promises work?
|
||||
|
||||
Before we can get into async/await, you should know what Promises are and how they work because async/await is just a way to handle Promises. If you know what Promises are and how to deal with them, you can skip this part.
|
||||
|
||||
Promises are a way to handle asynchronous tasks in JavaScript; they are the newer alternative to callbacks. A Promise has many similarities to a progress bar; they represent an unfinished and ongoing process. An excellent example of this is a request to a server (e.g., discord.js sends requests to Discord's API).
|
||||
|
||||
A Promise can have three states; pending, resolved, and rejected
|
||||
|
||||
The **pending** state means that the Promise still is ongoing and neither resolved nor rejected.
|
||||
The **resolved** state means that the Promise is done and executed without any errors.
|
||||
The **rejected** state means that the Promise encountered an error and could not execute correctly.
|
||||
|
||||
One important thing to know is that a Promise can only have one state simultaneously; it can never be pending and resolved, rejected and resolved, or pending and rejected. You may be asking, "How would that look in code?". Here is a small example:
|
||||
|
||||
<Alert title="Tip" type="success">
|
||||
This example uses ES6 code. If you do not know what that is, you should read up on that
|
||||
[here](/additional-info/es6-syntax.md).
|
||||
</Alert>
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js
|
||||
function deleteMessages(amount) {
|
||||
return new Promise((resolve) => {
|
||||
if (amount > 10) throw new Error("You can't delete more than 10 Messages at a time.");
|
||||
setTimeout(() => resolve('Deleted 10 messages.'), 2000);
|
||||
});
|
||||
}
|
||||
|
||||
deleteMessages(5)
|
||||
.then((value) => {
|
||||
// `deleteMessages` is complete and has not encountered any errors
|
||||
// the resolved value will be the string "Deleted 10 messages"
|
||||
})
|
||||
.catch((error) => {
|
||||
// `deleteMessages` encountered an error
|
||||
// the error will be an Error Object
|
||||
});
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
In this scenario, the _`deleteMessages`_ function returns a Promise. The _`.then()`_ method will trigger if the Promise resolves, and the _`.catch()`_ method if the Promise rejects. In the _`deleteMessages`_ function, the Promise is resolved after 2 seconds with the string "Deleted 10 messages.", so the _`.catch()`_ method will never be executed. You can also pass the _`.catch()`_ function as the second parameter of _`.then()`_.
|
||||
|
||||
## How to implement async/await
|
||||
|
||||
### Theory
|
||||
|
||||
The following information is essential to know before working with async/await. You can only use the _`await`_ keyword inside a function declared as _`async`_ (you put the _`async`_ keyword before the _`function`_ keyword or before the parameters when using a callback function).
|
||||
|
||||
A simple example would be:
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js
|
||||
async function declaredAsAsync() {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
or
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js
|
||||
const declaredAsAsync = async () => {
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
You can use that as well if you use the arrow function as an event listener.
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js
|
||||
client.on('event', async (first, last) => {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
An important thing to know is that a function declared as _`async`_ will always return a Promise. In addition to this, if you return something, the Promise will resolve with that value, and if you throw an error, it will reject the Promise with that error.
|
||||
|
||||
### Execution with discord.js code
|
||||
|
||||
Now that you know how Promises work and what they are used for, let's look at an example that handles multiple Promises. Let's say you want to react with letters (regional indicators) in a specific order. For this example, here's a basic template for a discord.js bot with some ES6 adjustments.
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js
|
||||
const { Client, GatewayIntentBits } = require('discord.js');
|
||||
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
||||
|
||||
client.once('ready', () => {
|
||||
console.log('I am ready!');
|
||||
});
|
||||
|
||||
client.on('interactionCreate', (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
if (interaction.commandName === 'react') {
|
||||
// ...
|
||||
}
|
||||
});
|
||||
|
||||
client.login('your-token-goes-here');
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
If you don't know how Node.js asynchronous execution works, you would probably try something like this:
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js mark=4:7
|
||||
client.on('interactionCreate', (interaction) => {
|
||||
// ...
|
||||
if (commandName === 'react') {
|
||||
const message = interaction.reply({ content: 'Reacting!', fetchReply: true });
|
||||
message.react('🇦');
|
||||
message.react('🇧');
|
||||
message.react('🇨');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
But since all of these methods are started at the same time, it would just be a race to which server request finished first, so there would be no guarantee that it would react at all (if the message isn't fetched) or in the order you wanted it to. In order to make sure it reacts after the message is sent and in order (a, b, c), you'd need to use the _`.then()`_ callback from the Promises that these methods return. The code would look like this:
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js mark=4:12
|
||||
client.on('interactionCreate', (interaction) => {
|
||||
// ...
|
||||
if (commandName === 'react') {
|
||||
interaction.reply({ content: 'Reacting!', fetchReply: true }).then((message) => {
|
||||
message
|
||||
.react('🇦')
|
||||
.then(() => message.react('🇧'))
|
||||
.then(() => message.react('🇨'))
|
||||
.catch((error) => {
|
||||
// handle failure of any Promise rejection inside here
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
In this piece of code, the Promises are [chain resolved](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then#Chaining) with each other, and if one of the Promises gets rejected, the function passed to _`.catch()`_ gets called. Here's the same code but with async/await:
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js mark=1,4:7
|
||||
client.on('interactionCreate', async (interaction) => {
|
||||
// ...
|
||||
if (commandName === 'react') {
|
||||
const message = await interaction.reply({ content: 'Reacting!', fetchReply: true });
|
||||
await message.react('🇦');
|
||||
await message.react('🇧');
|
||||
await message.react('🇨');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
It's mostly the same code, but how would you catch Promise rejections now since _`.catch()`_ isn't there anymore? That is also a useful feature with async/await; the error will be thrown if you await it so that you can wrap the awaited Promises inside a try/catch, and you're good to go.
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js mark=1,4:11
|
||||
client.on('interactionCreate', async (interaction) => {
|
||||
if (commandName === 'react') {
|
||||
try {
|
||||
const message = await interaction.reply({ content: 'Reacting!', fetchReply: true });
|
||||
await message.react('🇦');
|
||||
await message.react('🇧');
|
||||
await message.react('🇨');
|
||||
} catch (error) {
|
||||
// handle failure of any Promise rejection inside here
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
This code looks clean and is also easy to read.
|
||||
|
||||
So you may be asking, "How would I get the value the Promise resolved with?".
|
||||
|
||||
Let's look at an example where you want to delete a sent reply.
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js mark=3:10
|
||||
client.on('interactionCreate', (interaction) => {
|
||||
// ...
|
||||
if (commandName === 'delete') {
|
||||
interaction
|
||||
.reply({ content: 'This message will be deleted.', fetchReply: true })
|
||||
.then((replyMessage) => setTimeout(() => replyMessage.delete(), 10000))
|
||||
.catch((error) => {
|
||||
// handle error
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
The return value of a _`.reply()`_ with the _`fetchReply`_ option set to _`true`_ is a Promise which resolves with the reply when it has been sent, but how would the same code with async/await look?
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js mark=1,4:10
|
||||
client.on('interactionCreate', async (interaction) => {
|
||||
if (commandName === 'delete') {
|
||||
try {
|
||||
const replyMessage = await interaction.reply({ content: 'This message will be deleted.', fetchReply: true });
|
||||
setTimeout(() => replyMessage.delete(), 10000);
|
||||
} catch (error) {
|
||||
// handle error
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
With async/await, you can assign the awaited function to a variable representing the returned value. Now you know how you use async/await.
|
||||
123
apps/guide/src/content/additional-info/collections.mdx
Normal file
123
apps/guide/src/content/additional-info/collections.mdx
Normal file
@@ -0,0 +1,123 @@
|
||||
---
|
||||
title: Collections
|
||||
category: Additional info
|
||||
---
|
||||
|
||||
# Collections
|
||||
|
||||
discord.js comes with a utility class known as _`Collection`_.
|
||||
It extends JavaScript's native _`Map`_ class, so it has all the _`Map`_ features and more!
|
||||
|
||||
<Alert title="Warning" type="warning">
|
||||
If you're not familiar with _`Map`_, read [MDN's page on
|
||||
it](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) before continuing. You
|
||||
should be familiar with _`Array`_
|
||||
[methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) as well. We will
|
||||
also use some ES6 features, so read up [here](/additional-info/es6-syntax.md) if you do not know what they are.
|
||||
</Alert>
|
||||
|
||||
A _`Map`_ allows for an association between unique keys and their values.
|
||||
For example, how can you transform every value or filter the entries in a _`Map`_ easily?
|
||||
This is the point of the _`Collection`_ class!
|
||||
|
||||
## Array-like Methods
|
||||
|
||||
Many of the methods on _`Collection`_ correspond to their namesake in _`Array`_. One of them is _`find`_:
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js
|
||||
// Assume we have an array of users and a collection of the same users.
|
||||
array.find((u) => u.discriminator === '1000');
|
||||
collection.find((u) => u.discriminator === '1000');
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
The interface of the callback function is very similar between the two.
|
||||
For arrays, callbacks usually pass the parameters _`(value, index, array)`_, where _`value`_ is the value iterated to,
|
||||
_`index`_ is the current index, and _`array`_ is the array. For collections, you would have _`(value, key, collection)`_.
|
||||
Here, _`value`_ is the same, but _`key`_ is the key of the value, and _`collection`_ is the collection itself instead.
|
||||
|
||||
Methods that follow this philosophy of staying close to the _`Array`_ interface are as follows:
|
||||
|
||||
- _`find`_
|
||||
- _`filter`_ - Note that this returns a _`Collection`_ rather than an _`Array`_.
|
||||
- _`map`_ - Yet this returns an _`Array`_ of values instead of a _`Collection`_!
|
||||
- _`every`_
|
||||
- _`some`_
|
||||
- _`reduce`_
|
||||
- _`concat`_
|
||||
- _`sort`_
|
||||
|
||||
## Converting to Array
|
||||
|
||||
Since _`Collection`_ extends _`Map`_, it is an [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols), and can be converted to an _`Array`_ through either _`Array.from()`_ or spread syntax (_`...collection`_).
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js
|
||||
// For values.
|
||||
Array.from(collection.values());
|
||||
[...collection.values()];
|
||||
|
||||
// For keys.
|
||||
Array.from(collection.keys());
|
||||
[...collection.keys()];
|
||||
|
||||
// For [key, value] pairs.
|
||||
Array.from(collection);
|
||||
[...collection];
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
<Alert title="Warning" type="warning">
|
||||
Many people convert Collections to Arrays way too much! This can lead to unnecessary and confusing code. Before you
|
||||
use _`Array.from()`_ or similar, ask yourself if whatever you are trying to do can't be done with the given _`Map`_ or
|
||||
_`Collection`_ methods or with a for-of loop.
|
||||
</Alert>
|
||||
|
||||
## Extra Utilities
|
||||
|
||||
Some methods are not from _`Array`_ and are instead entirely new to standard JavaScript.
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js
|
||||
// A random value.
|
||||
collection.random();
|
||||
|
||||
// The first value.
|
||||
collection.first();
|
||||
|
||||
// The first 5 values.
|
||||
collection.first(5);
|
||||
|
||||
// Similar to `first`, but from the end.
|
||||
collection.last();
|
||||
collection.last(2);
|
||||
|
||||
// Removes anything that meets the condition from the collection.
|
||||
// Sort of like `filter`, but in-place.
|
||||
collection.sweep((user) => user.username === 'Bob');
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
A more complicated method is _`partition`_, which splits a single Collection into two new Collections based on the provided function.
|
||||
You can think of it as two \_`filter`\_s, but done at the same time:
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js
|
||||
// `bots` is a Collection of users where their `bot` property was true.
|
||||
// `humans` is a Collection where the property was false instead!
|
||||
const [bots, humans] = collection.partition((u) => u.bot);
|
||||
|
||||
// Both return true.
|
||||
bots.every((b) => b.bot);
|
||||
humans.every((h) => !h.bot);
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
244
apps/guide/src/content/creating-your-bot/creating-commands.mdx
Normal file
244
apps/guide/src/content/creating-your-bot/creating-commands.mdx
Normal file
@@ -0,0 +1,244 @@
|
||||
---
|
||||
title: Creating commands
|
||||
category: Creating your bot
|
||||
---
|
||||
|
||||
# Creating commands
|
||||
|
||||
<Alert title="Tip" type="success">
|
||||
This page is a follow-up and bases its code on [the previous page](/creating-your-bot/).
|
||||
</Alert>
|
||||
|
||||
<DiscordMessages rounded>
|
||||
<DiscordMessage
|
||||
interaction={{
|
||||
author: {
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
},
|
||||
command: 'ping',
|
||||
}}
|
||||
author={{
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
time: 'Today at 21:00',
|
||||
}}
|
||||
>
|
||||
Pong!
|
||||
</DiscordMessage>
|
||||
</DiscordMessages>
|
||||
|
||||
Discord allows developers to register [slash commands](https://discord.com/developers/docs/interactions/application-commands), which provide users a first-class way of interacting directly with your application. Before being able to reply to a command, you must first register it.
|
||||
|
||||
## Registering commands
|
||||
|
||||
This section will cover only the bare minimum to get you started, but you can refer to our [in-depth page on registering slash commands](/interactions/slash-commands.md#registering-slash-commands) for further details. It covers guild commands, global commands, options, option types, and choices.
|
||||
|
||||
### Command deployment script
|
||||
|
||||
Create a _`deploy-commands.js`_ file in your project directory. This file will be used to register and update the slash commands for your bot application.
|
||||
|
||||
Since commands only need to be registered once, and updated when the definition (description, options etc) is changed, it's not necessary to connect a whole client to the gateway or do this on every _`ready`_ event. As such, a standalone script using the lighter REST manager is preferred.
|
||||
|
||||
Below is a deployment script you can use. Focus on these variables:
|
||||
|
||||
- _`clientId`_: Your application's client id
|
||||
- _`guildId`_: Your development server's id
|
||||
- _`commands`_: An array of commands to register. The [slash command builder](/popular-topics/builders.md#slash-command-builders) from _`discord.js`_ is used to build the data for your commands
|
||||
|
||||
<Alert title="Tip" type="success">
|
||||
In order to get your application's client id, go to [Discord Developer
|
||||
Portal](https://discord.com/developers/applications) and choose your application. Find the id under "Application ID"
|
||||
in General Information subpage. To get guild id, open Discord and go to your settings. On the "Advanced" page, turn on
|
||||
"Developer Mode". This will enable a "Copy ID" button in the context menu when you right-click on a server icon, a
|
||||
user's profile, etc.
|
||||
</Alert>
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js deploy-commands.js mark=4,6:10
|
||||
const { REST, SlashCommandBuilder, Routes } = require('discord.js');
|
||||
const { clientId, guildId, token } = require('./config.json');
|
||||
|
||||
const commands = [
|
||||
new SlashCommandBuilder().setName('ping').setDescription('Replies with pong!'),
|
||||
new SlashCommandBuilder().setName('server').setDescription('Replies with server info!'),
|
||||
new SlashCommandBuilder().setName('user').setDescription('Replies with user info!'),
|
||||
].map((command) => command.toJSON());
|
||||
|
||||
const rest = new REST({ version: '10' }).setToken(token);
|
||||
|
||||
rest
|
||||
.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands })
|
||||
.then((data) => console.log(`Successfully registered ${data.length} application commands.`))
|
||||
.catch(console.error);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
```json config.json mark=2:3
|
||||
{
|
||||
"clientId": "123456789012345678",
|
||||
"guildId": "876543210987654321",
|
||||
"token": "your-token-goes-here"
|
||||
}
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
Once you fill in these values, run _`node deploy-commands.js`_ in your project directory to register your commands to a single guild. It's also possible to [register commands globally](/interactions/slash-commands.md#global-commands).
|
||||
|
||||
<Alert title="Tip" type="success">
|
||||
You only need to run `node deploy-commands.js` once. You should only run it again if you add or edit existing
|
||||
commands.
|
||||
</Alert>
|
||||
|
||||
## Replying to commands
|
||||
|
||||
Once you've registered your commands, you can listen for interactions via <DocsLink path="class/Client?scrollTo=e-interactionCreate" /> in your _`index.js`_ file.
|
||||
|
||||
You should first check if an interaction is a chat input command via <DocsLink path="class/Interaction?scrollTo=isChatInputCommand" type="method">_`.isChatInputCommand()`_</DocsLink>, and then check the <DocsLink path="class/CommandInteraction?scrollTo=commandName">_`.commandName`_</DocsLink> property to know which command it is. You can respond to interactions with <DocsLink path="class/CommandInteraction?scrollTo=reply">_`.reply()`_</DocsLink>.
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js mark=5:16
|
||||
client.once('ready', () => {
|
||||
console.log('Ready!');
|
||||
});
|
||||
|
||||
client.on('interactionCreate', async (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
const { commandName } = interaction;
|
||||
if (commandName === 'ping') {
|
||||
await interaction.reply('Pong!');
|
||||
} else if (commandName === 'server') {
|
||||
await interaction.reply('Server info.');
|
||||
} else if (commandName === 'user') {
|
||||
await interaction.reply('User info.');
|
||||
}
|
||||
});
|
||||
client.login(token);
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
### Server info command
|
||||
|
||||
Note that servers are referred to as "guilds" in the Discord API and discord.js library. _`interaction.guild`_ refers to the guild the interaction was sent in (a <DocsLink path="class/Guild" /> instance), which exposes properties such as _`.name`_ or _`.memberCount`_.
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js focus=7
|
||||
client.on('interactionCreate', async (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
const { commandName } = interaction;
|
||||
if (commandName === 'ping') {
|
||||
await interaction.reply('Pong!');
|
||||
} else if (commandName === 'server') {
|
||||
await interaction.reply(`Server name: ${interaction.guild.name}\nTotal members: ${interaction.guild.memberCount}`);
|
||||
} else if (commandName === 'user') {
|
||||
await interaction.reply('User info.');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
<DiscordMessages rounded>
|
||||
<DiscordMessage
|
||||
interaction={{
|
||||
author: {
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
},
|
||||
command: 'server',
|
||||
}}
|
||||
author={{
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
time: 'Today at 21:00',
|
||||
}}
|
||||
>
|
||||
<p>Server name: discord.js Guide</p>
|
||||
<p>Total members: 2</p>
|
||||
</DiscordMessage>
|
||||
</DiscordMessages>
|
||||
|
||||
You could also display the date the server was created, or the server's verification level. You would do those in the same manner – use _`interaction.guild.createdAt`_ or _`interaction.guild.verificationLevel`_, respectively.
|
||||
|
||||
<Alert title="Tip" type="success">
|
||||
Refer to the <DocsLink path="class/Guild" /> documentation for a list of all the available properties and methods!
|
||||
</Alert>
|
||||
|
||||
### User info command
|
||||
|
||||
A "user" refers to a Discord user. _`interaction.user`_ refers to the user the interaction was sent by (a <DocsLink path="class/User" /> instance), which exposes properties such as _`.tag`_ or _`.id`_.
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js focus=9
|
||||
client.on('interactionCreate', async (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
const { commandName } = interaction;
|
||||
if (commandName === 'ping') {
|
||||
await interaction.reply('Pong!');
|
||||
} else if (commandName === 'server') {
|
||||
await interaction.reply(`Server name: ${interaction.guild.name}\nTotal members: ${interaction.guild.memberCount}`);
|
||||
} else if (commandName === 'user') {
|
||||
await interaction.reply(`Your tag: ${interaction.user.tag}\nYour id: ${interaction.user.id}`);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
<DiscordMessages rounded>
|
||||
<DiscordMessage
|
||||
interaction={{
|
||||
author: {
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
},
|
||||
command: 'user',
|
||||
}}
|
||||
author={{
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
time: 'Today at 21:00',
|
||||
}}
|
||||
>
|
||||
<p>Your tag: User#0001</p>
|
||||
<p>Your id: 123456789012345678</p>
|
||||
</DiscordMessage>
|
||||
</DiscordMessages>
|
||||
|
||||
<Alert title="Tip" type="success">
|
||||
Refer to the <DocsLink path="class/User" /> documentation for a list of all the available properties and methods!
|
||||
</Alert>
|
||||
|
||||
And there you have it!
|
||||
|
||||
## The problem with if/else if
|
||||
|
||||
If you don't plan on making more than a couple commands, then using an _`if`_/_`else if`_ chain is fine; however, this isn't always the case. Using a giant _`if`_/_`else if`_ chain will only hinder your development process in the long run.
|
||||
|
||||
Here's a small list of reasons why you shouldn't do so:
|
||||
|
||||
- Takes longer to find a piece of code you want;
|
||||
- Easier to fall victim to [spaghetti code](https://en.wikipedia.org/wiki/Spaghetti_code);
|
||||
- Difficult to maintain as it grows;
|
||||
- Difficult to debug;
|
||||
- Difficult to organize;
|
||||
- General bad practice.
|
||||
|
||||
Next, we'll be diving into something called a "command handler" – code that makes handling commands easier and much more efficient. This allows you to move your commands into individual files.
|
||||
|
||||
## Resulting code
|
||||
|
||||
<ResultingCode />
|
||||
188
apps/guide/src/content/creating-your-bot/index.mdx
Normal file
188
apps/guide/src/content/creating-your-bot/index.mdx
Normal file
@@ -0,0 +1,188 @@
|
||||
---
|
||||
title: Initial files
|
||||
category: Creating your bot
|
||||
---
|
||||
|
||||
# Initial files
|
||||
|
||||
Once you [add your bot to a server](/preparations/adding-your-bot-to-servers.md), the next step is to start coding and get it online! Let's start by creating a config file for your client token and a main file for your bot application.
|
||||
|
||||
## Creating configuration files
|
||||
|
||||
As explained in the ["What is a token, anyway?"](/preparations/setting-up-a-bot-application.md#what-is-a-token-anyway) section, your token is essentially your bot's password, and you should protect it as best as possible. This can be done through a _`config.json`_ file or by using environment variables.
|
||||
|
||||
Open your application in the [Discord Developer Portal](https://discord.com/developers/applications) and go to the "Bot" page to copy your token.
|
||||
|
||||
### Using config.json
|
||||
|
||||
Storing data in a _`config.json`_ file is a common way of keeping your sensitive values safe. Create a _`config.json`_ file in your project directory and paste in your token. You can access your token inside other files by using _`require()`_.
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```json config.json
|
||||
{
|
||||
"token": "your-token-goes-here"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
```js Usage
|
||||
const { token } = require('./config.json');
|
||||
|
||||
console.log(token);
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
<Alert title="Caution" type="danger">
|
||||
If you're using Git, you should not commit this file and should [ignore it via
|
||||
_`.gitignore`_](/creating-your-bot/#git-and-gitignore).
|
||||
</Alert>
|
||||
|
||||
### Using environment variables
|
||||
|
||||
Environment variables are special values for your environment (e.g., terminal session, Docker container, or environment variable file). You can pass these values into your code's scope so that you can use them.
|
||||
|
||||
One way to pass in environment variables is via the command line interface. When starting your app, instead of _`node index.js`_, use _`TOKEN=your-token-goes-here node index.js`_. You can repeat this pattern to expose other values as well.
|
||||
|
||||
You can access the set values in your code via the _`process.env`_ global variable, accessible in any file. Note that values passed this way will always be strings and that you might need to parse them to a number, if using them to do calculations.
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```shellscript Command line
|
||||
A=123 B=456 DISCORD_TOKEN=your-token-goes-here node index.js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
```js Usage
|
||||
console.log(process.env.A);
|
||||
console.log(process.env.B);
|
||||
console.log(process.env.DISCORD_TOKEN);
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
#### Using dotenv
|
||||
|
||||
Another common approach is storing these values in a _`.env`_ file. This spares you from always copying your token into the command line. Each line in a _`.env`_ file should hold a _`KEY=value`_ pair.
|
||||
|
||||
You can use the [_`dotenv`_ package](https://www.npmjs.com/package/dotenv) for this. Once installed, require and use the package to load your _`.env`_ file and attach the variables to _`process.env`_:
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```sh npm
|
||||
npm install dotenv
|
||||
```
|
||||
|
||||
```sh yarn
|
||||
yarn add dotenv
|
||||
```
|
||||
|
||||
```sh pnpm
|
||||
pnpm add dotenv
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
```text .env
|
||||
A=123
|
||||
B=456
|
||||
DISCORD_TOKEN=your-token-goes-here
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
```js Usage
|
||||
const dotenv = require('dotenv');
|
||||
|
||||
dotenv.config();
|
||||
|
||||
console.log(process.env.A);
|
||||
console.log(process.env.B);
|
||||
console.log(process.env.DISCORD_TOKEN);
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
<Alert title="Caution" type="danger">
|
||||
If you're using Git, you should not commit this file and should [ignore it via
|
||||
_`.gitignore`_](/creating-your-bot/#git-and-gitignore).
|
||||
</Alert>
|
||||
|
||||
<Section title="Online editors (Glitch, Heroku, Replit, etc.)" defaultClosed padded background gutter>
|
||||
While we generally do not recommend using online editors as hosting solutions, but rather invest in a proper virtual private server, these services do offer ways to keep your credentials safe as well! Please see the respective service's documentation and help articles for more information on how to keep sensitive values safe:
|
||||
|
||||
- Glitch: [Storing secrets in .env](https://glitch.happyfox.com/kb/article/18)
|
||||
- Heroku: [Configuration variables](https://devcenter.heroku.com/articles/config-vars)
|
||||
- Replit: [Secrets and environment variables](https://docs.replit.com/repls/secrets-environment-variables)
|
||||
|
||||
</Section>
|
||||
|
||||
### Git and .gitignore
|
||||
|
||||
Git is a fantastic tool to keep track of your code changes and allows you to upload progress to services like [GitHub](https://github.com/), [GitLab](https://about.gitlab.com/), or [Bitbucket](https://bitbucket.org/product). While this is super useful to share code with other developers, it also bears the risk of uploading your configuration files with sensitive values!
|
||||
|
||||
You can specify files that Git should ignore in its versioning systems with a _`.gitignore`_ file. Create a _`.gitignore`_ file in your project directory and add the names of the files and folders you want to ignore:
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```
|
||||
node_modules
|
||||
.env
|
||||
config.json
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
<Alert title="Tip" type="success">
|
||||
Aside from keeping credentials safe, _`node_modules`_ should be included here. Since this directory can be restored
|
||||
based on the entries in your _`package.json`_ and _`package-lock.json`_ files by running _`npm install`_, it does not
|
||||
need to be included in Git. You can specify quite intricate patterns in _`.gitignore`_ files, check out the [Git
|
||||
documentation on _`.gitignore`_](https://git-scm.com/docs/gitignore) for more information!
|
||||
</Alert>
|
||||
|
||||
## Creating the main file
|
||||
|
||||
Open your code editor and create a new file. We suggest that you save the file as _`index.js`_, but you may name it whatever you wish.
|
||||
|
||||
Here's the base code to get you started:
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```js
|
||||
// Require the necessary discord.js classes
|
||||
const { Client, GatewayIntentBits } = require('discord.js');
|
||||
const { token } = require('./config.json');
|
||||
|
||||
// Create a new client instance
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
||||
|
||||
// When the client is ready, run this code (only once)
|
||||
client.once('ready', () => {
|
||||
console.log('Ready!');
|
||||
});
|
||||
|
||||
// Login to Discord with your client's token
|
||||
client.login(token);
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
This is how you create a client instance for your Discord bot and login to Discord. The _`GatewayIntentBits.Guilds`_ intents option is necessary for your client to work properly, as it ensures that the caches for guilds, channels and roles are populated and available for internal use.
|
||||
|
||||
Intents also define which events Discord should send to your bot, and you may wish to enable more than just the minimum. You can read more about the other intents on the [Intents topic](/popular-topics/intents).
|
||||
|
||||
Open your terminal and run _`node index.js`_ to start the process. If you see "Ready!" after a few seconds, you're good to go!
|
||||
|
||||
<Alert title="Tip" type="success">
|
||||
You can open your _`package.json`_ file and edit the _`"main": "index.js"`_ field to point to your main file. You can
|
||||
then run _`node .`_ in your terminal to start the process! After closing the process with _`Ctrl + C`_, you can press
|
||||
the up arrow on your keyboard to bring up the latest commands you've run. Pressing up and then enter after closing the
|
||||
process is a quick way to start it up again.
|
||||
</Alert>
|
||||
|
||||
## Resulting code
|
||||
|
||||
<ResultingCode path="creating-your-bot/initial-files" />
|
||||
35
apps/guide/src/content/index.mdx
Normal file
35
apps/guide/src/content/index.mdx
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
title: Introduction
|
||||
category: Home
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
If you're reading this, it probably means you want to learn how to make a bot with discord.js. Awesome! You've come to the right place.
|
||||
This guide will teach you things such as:
|
||||
|
||||
- How to get a bot [up and running](/preparations/) from scratch;
|
||||
- How to properly [create](/creating-your-bot/), [organize](/creating-your-bot/command-handling.md), and expand on your commands;
|
||||
- In-depth explanations and examples regarding popular topics (e.g. [reactions](/popular-topics/reactions.md), [embeds](/popular-topics/embeds.md), [canvas](/popular-topics/canvas.md));
|
||||
- Working with databases (e.g. [sequelize](/sequelize/) and [keyv](/keyv/));
|
||||
- Getting started with [sharding](/sharding/);
|
||||
- And much more.
|
||||
|
||||
This guide will also cover subjects like common errors and how to solve them, keeping your code clean, setting up a proper development environment, etc.
|
||||
Sounds good? Great! Let's get started, then.
|
||||
|
||||
## Before you begin...
|
||||
|
||||
Alright, making a bot is cool and all, but there are some prerequisites to it. To create a bot with discord.js, you should have a fairly decent grasp of JavaScript itself.
|
||||
While you _can_ make a bot with very little JavaScript and programming knowledge, trying to do so without understanding the language first will only hinder you. You may get stuck on many uncomplicated issues, struggle with solutions to incredibly easy problems, and all-in-all end up frustrated. Sounds pretty annoying.
|
||||
|
||||
If you don't know JavaScript but would like to learn about it, here are a few links to help get you started:
|
||||
|
||||
- [Eloquent JavaScript, a free online book](http://eloquentjavascript.net/)
|
||||
- [JavaScript.info, a modern javascript tutorial](https://javascript.info/)
|
||||
- [Codecademy's interactive JavaScript course](https://www.codecademy.com/learn/introduction-to-javascript)
|
||||
- [Nodeschool, for both JavaScript and Node.js lessons](https://nodeschool.io/)
|
||||
- [MDN's JavaScript guide and full documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
||||
- [Google, your best friend](https://google.com)
|
||||
|
||||
Take your pick, learn some JavaScript, and once you feel like you're confident enough to make a bot, come back and get started!
|
||||
17
apps/guide/src/content/requesting-more-content.mdx
Normal file
17
apps/guide/src/content/requesting-more-content.mdx
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
title: Requesting more content
|
||||
category: Home
|
||||
---
|
||||
|
||||
# Requesting more content
|
||||
|
||||
Since this guide is made specifically for the discord.js community, we want to be sure to provide the most relevant and up-to-date content. We will, of course, make additions to the current pages and add new ones as we see fit, but fulfilling requests is how we know we're providing content you all want the most.
|
||||
|
||||
Requests may be as simple as "add an example to the [frequently asked questions](/popular-topics/faq.html) page", or as elaborate as "add a page regarding [sharding](/sharding/)". We'll do our best to fulfill all requests, as long as they're reasonable.
|
||||
|
||||
To make a request, simply head over to [the repo's issue tracker](https://github.com/discordjs/guide/issues) and [create a new issue](https://github.com/discordjs/guide/issues/new)! Title it appropriately, and let us know exactly what you mean inside the issue description. Make sure that you've looked around the site before making a request; what you want to request might already exist!
|
||||
|
||||
<Alert title="Tip" type="success">
|
||||
Remember that you can always [fork the repo](https://github.com/discordjs/guide) and [make a pull
|
||||
request](https://github.com/discordjs/guide/pulls) if you want to add anything to the guide yourself!
|
||||
</Alert>
|
||||
100
apps/guide/src/content/test.mdx
Normal file
100
apps/guide/src/content/test.mdx
Normal file
@@ -0,0 +1,100 @@
|
||||
---
|
||||
title: Test
|
||||
category: Test
|
||||
---
|
||||
|
||||
<DiscordMessages>
|
||||
<DiscordMessage
|
||||
reply={{
|
||||
author: {
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
},
|
||||
content: 'Test',
|
||||
}}
|
||||
author={{
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
time: 'Today at 21:00',
|
||||
}}
|
||||
>
|
||||
1234
|
||||
</DiscordMessage>
|
||||
<DiscordMessage
|
||||
author={{
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
time: 'Today at 21:00',
|
||||
}}
|
||||
followUp
|
||||
time="21:02"
|
||||
>
|
||||
1234
|
||||
</DiscordMessage>
|
||||
</DiscordMessages>
|
||||
|
||||
<DiscordMessages>
|
||||
<DiscordMessage
|
||||
reply={{
|
||||
author: {
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
},
|
||||
content: 'Test',
|
||||
}}
|
||||
author={{
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
time: 'Today at 21:00',
|
||||
}}
|
||||
>
|
||||
1234
|
||||
</DiscordMessage>
|
||||
</DiscordMessages>
|
||||
|
||||
<DiscordMessages>
|
||||
<DiscordMessage
|
||||
reply={{
|
||||
author: {
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
},
|
||||
content: 'Test',
|
||||
}}
|
||||
author={{
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
time: 'Today at 21:00',
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<DiscordMessageEmbed
|
||||
author={{
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
}}
|
||||
/>
|
||||
<DiscordMessageEmbed title={{ title: 'Title' }} />
|
||||
<DiscordMessageEmbed footer={{ content: 'Footer' }} />
|
||||
<DiscordMessageEmbed
|
||||
author={{
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
}}
|
||||
title={{ title: 'Title' }}
|
||||
footer={{ content: 'Footer' }}
|
||||
>
|
||||
Test
|
||||
</DiscordMessageEmbed>
|
||||
</>
|
||||
</DiscordMessage>
|
||||
</DiscordMessages>
|
||||
71
apps/guide/src/content/whats-new.mdx
Normal file
71
apps/guide/src/content/whats-new.mdx
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: What's new
|
||||
category: Home
|
||||
---
|
||||
|
||||
# What's new
|
||||
|
||||
<DiscordMessages rounded>
|
||||
<DiscordMessage
|
||||
interaction={{
|
||||
author: {
|
||||
avatar:
|
||||
'https://cdn.discordapp.com/guilds/222078108977594368/users/81440962496172032/avatars/c059c5d04d717ea05790f7a6447e4843.webp?size=160',
|
||||
username: 'Crawl',
|
||||
},
|
||||
command: 'upgrade',
|
||||
}}
|
||||
author={{
|
||||
avatar: 'https://cdn.discordapp.com/avatars/474807795183648809/7f239a0776ff928b2182906a2b3743c9.webp?size=160',
|
||||
bot: true,
|
||||
username: 'Guide Bot',
|
||||
time: 'Today at 21:00',
|
||||
}}
|
||||
>
|
||||
discord.js v14 has released and the guide has been updated!
|
||||
<br />
|
||||
This includes additions and changes made in Discord, such as slash commands and message components.
|
||||
</DiscordMessage>
|
||||
</DiscordMessages>
|
||||
|
||||
## Site
|
||||
|
||||
- Upgraded to [VuePress v2](https://v2.vuepress.vuejs.org/)
|
||||
- New theme made to match the [discord.js documentation site](https://discord.js.org/)
|
||||
- Discord message components upgraded to [@discord-message-components/vue](https://github.com/Danktuary/discord-message-components/blob/main/packages/vue/README.md)
|
||||
- Many fixes in code blocks, grammar, consistency, etc.
|
||||
|
||||
## Pages
|
||||
|
||||
All content has been updated to use discord.js v14 syntax. The v13 version of the guide can be found at [https://v13.discordjs.guide/](https://v13.discordjs.guide/).
|
||||
|
||||
### New
|
||||
|
||||
- [Updating from v13 to v14](/additional-info/changes-in-v14.md): A list of the changes from discord.js v13 to v14
|
||||
- [Slash commands](/interactions/slash-commands.md): Registering, replying to slash commands and permissions
|
||||
- [Buttons](/interactions/buttons.md): Building, sending, and receiving buttons
|
||||
- [Select menus](/interactions/select-menus.md): Building, sending, and receiving select menus
|
||||
- [Threads](/popular-topics/threads.md): Creating and managing threads
|
||||
- [Builders](/popular-topics/builders.md): A collection of builders to use with your bot
|
||||
|
||||
### Updated
|
||||
|
||||
- Commando: Replaced with [Sapphire](https://sapphirejs.dev/docs/Guide/getting-started/getting-started-with-sapphire)
|
||||
- [Voice](/voice/): Rewritten to use the [_`@discordjs/voice`_](https://github.com/discordjs/discord.js/tree/main/packages/voice) package
|
||||
- [Command handling](/creating-your-bot/command-handling.md/): Updated to use slash commands
|
||||
- Obsolete sections removed
|
||||
- _`client.on('message')`_ snippets updated to _`client.on('interactionCreate')`_
|
||||
- [Message content will become a new privileged intent on August 31, 2022](https://support-dev.discord.com/hc/en-us/articles/4404772028055)
|
||||
|
||||
<DiscordMessages rounded>
|
||||
<DiscordMessage
|
||||
author={{
|
||||
avatar: 'https://cdn.discordapp.com/avatars/474807795183648809/7f239a0776ff928b2182906a2b3743c9.webp?size=160',
|
||||
bot: true,
|
||||
username: 'Guide Bot',
|
||||
time: 'Today at 21:00',
|
||||
}}
|
||||
>
|
||||
Thank you to all of those that contributed to the development of discord.js and the guide!
|
||||
</DiscordMessage>
|
||||
</DiscordMessages>
|
||||
Reference in New Issue
Block a user