Skip to content

Commit bc6005f

Browse files
almostSoujiJiraliteQjuhimnaiyarvladfrangu
authored
feat(guide): port legacy guide (#10938)
* feat: initial attempt at porting legacy guide * feat: completion of legacy guide backport * chore: lockfile shenanigans * fix: handle svgs * fix: replace svg with mermaid integration * chore: format * chore: remove unnecssary bullet * chore: cleanup code highlights * chore: explicit return * chore: move display components after interactive components in sidebar * chore: voice * top link should be installation * add docs link to sidebar * feat: subguide-based accent styles * chore: don't list faq twice * chore: mention display components in interactive components * fix: remove unoccs/order rule from guide * chore: redirect to legacy guide instead of /guide root * refactor: use `<kbd>` * refactor: more kbd use * Update apps/guide/content/docs/legacy/app-creation/handling-events.mdx Co-authored-by: Naiyar <[email protected]> * chore: fix typos Co-authored-by: Qjuh <[email protected]> * chore: fix typos * chore: fix links regarding secret stores across coding platforms * chore: fix typo * chore: link node method directly Co-authored-by: Qjuh <[email protected]> * chore: typos Co-authored-by: Vlad Frangu <[email protected]> * chore: typo Co-authored-by: Vlad Frangu <[email protected]> * fix: prevent v14 changes from being listed twice * chore: prefer relative links * chore: missed link conversion * chore: missed link conversion * chore: fix link * chore: remove legacy code highlight markers * chore: rephrase and extend contributing guidelines * feat(setup): suggest cli flag over dotenv package * chore: move introduction in sidebar better navigation experience if the 'next page' in intro refers to getting started vs. updating/faq * fix: replace outdated link * fix: update voice dependencies * chore: update node install instructions * fix: list in missing access callout * chore: match bun env file format * chore: restore ffmpeg disclaimer * fix: lockfile conflict * chore: action row typo Co-authored-by: Vlad Frangu <[email protected]> * chore: no longer use at-next for pino --------- Co-authored-by: Jiralite <[email protected]> Co-authored-by: Qjuh <[email protected]> Co-authored-by: Naiyar <[email protected]> Co-authored-by: Vlad Frangu <[email protected]>
1 parent ee3ca6f commit bc6005f

File tree

136 files changed

+11847
-48
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

136 files changed

+11847
-48
lines changed

apps/guide/CONTRIBUTING.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# Contributing
2+
3+
## Local development
4+
5+
Clone the code base into a local folder, `cd` into it, and install the dependencies:
6+
7+
```bash
8+
git clone https://github.com/discordjs/discord.js.git
9+
cd discord.js/apps/guide
10+
pnpm --filter guide install
11+
```
12+
13+
You can and should use `pnpm dev` to check your changes out locally before pushing them for review.
14+
15+
## Adding pages
16+
17+
To add a new page to the guide, create a `filename.mdx` file in the folder of your choice located under `/content`. Fumadocs will pick it up and route appropriately. To list the section in the sidebar, make sure it is listed in the `meta.json` file of the directory you placed it in under the `pages` key. The order in the `pages` array determines the order pages have in the sidebar.
18+
19+
## Framework and components
20+
21+
The guide uses the fumadocs documention framework for Next.js. You can find examples as well as documentation for the components you can use at <https://fumadocs.dev/docs/ui>.
22+
23+
## General guidelines
24+
25+
Please try your best to follow the guidelines below. They help to make the guide appear as a coherent piece of work rather than a collection of disconnected pieces with different writing styles.
26+
27+
### Spelling, grammar, and wording
28+
29+
Improper grammar, strange wording, and incorrect spelling are all things that may lead to confusion when a user reads a guide page. It's important to attempt to keep the content clear and consistent. Re-read what you've written and place yourself in the shoes of someone else for a moment to see if you can fully understand everything without any confusion.
30+
31+
Don't worry if you aren't super confident with your grammar/spelling/wording skills; all pull requests get thoroughly reviewed, and comments are left in areas that need to be fixed or could be done better/differently.
32+
33+
#### "You"/"your" instead of "we"/"our"
34+
35+
When explaining parts of the guide, we recommend to use "you" instead of "we" when referring to the read or things they can do:
36+
37+
```diff
38+
- To check our Node version, we can run `node -v`.
39+
+ To check your Node version, you can run `node -v`.
40+
41+
- To delete a message, we can do: `message.delete();`
42+
+ To delete a message, you can do: `message.delete();`
43+
44+
- Our final code should look like this: ...
45+
+ Your final code should look like this: ...
46+
47+
- Before we can actually do this, we need to update our configuration file.
48+
+ Before you can actually do this, you need to update your configuration file.
49+
```
50+
51+
#### "We" instead of "I"
52+
53+
When referring to yourself, use "we" (as in "the writers of this guide") instead of "I". For example:
54+
55+
```diff
56+
- If you don't already have this package installed, I would highly recommend doing so.
57+
+ If you don't already have this package installed, we would highly recommend doing so.
58+
# Valid alternative:
59+
+ If you don't already have this package installed, it's highly recommended that you do so.
60+
61+
- In this section, I'll be covering how to do that really cool thing everyone's asking about.
62+
+ In this section, we'll be covering how to do that really cool thing everyone's asking about.
63+
```
64+
65+
#### Inclusive language
66+
67+
Try to avoid using genered and otherwise non-inclusive language. The following are just examples to give you an idea of what we expect. Don't understand this as a complete list of "banned terms":
68+
69+
- Use they/them/their instead of gendered pronouns (he/him/his, she/her/hers).
70+
- Avoid using "master" and "slave", you can use "primary" and "replica" or "secondary" instead.
71+
- Avoid gendered terms like "guys", "folks" and "people" work just as well.
72+
- Avoid ableist terms "sanity check", use "confidence check" or "coherence check" instead.
73+
- Avoid talking about "dummy" values, call them "placeholder" or "sample value" instead.
74+
75+
### Paragraph structure
76+
77+
Try to keep guide articles formatted nicely and easy to read. If paragraphs get too long, you can usually split them up where they introduce a new concept or facet. Adding a bit of spacing can make the guide easier to digest and follow! Try to avoid run-on sentences with many embedded clauses.
78+
79+
## Semantic components
80+
81+
You can find the full documentation for the guide framework at <https://fumadocs.dev/docs/ui/>. If you are unsure what to use when, consider looking through the existing guide pages and how they approach things.
82+
83+
### Callouts
84+
85+
You can use [Callouts](https://fumadocs.dev/docs/ui/markdown#callouts) to describe additional context that doesn't fully fit into the flow of the paragraph or requires special attention. Prefer to MDX syntax `<Callout />` over Remark `:::` admonitions.
86+
87+
### Code
88+
89+
Fumadocs integrates [Shiki transformers](https://fumadocs.dev/docs/ui/markdown#shiki-transformers) for visual highlighting through the use of [Rhype Code](https://fumadocs.dev/docs/headless/mdx/rehype-code).
90+
91+
When describing changes or additions to code, prefer using the appropriate language (`js` in most cases for this guide) with diff transformers over `diff` highlights:
92+
93+
```js
94+
console.log('Hello'); // [!code --]
95+
console.log('Hello World'); // [!code ++]
96+
```
97+
98+
You can put the transfomer syntax above the respective line and declare ranges instead of repeating formatting intsructions. You can also combine different transformers on the same line. Note that word highlights highlight the word across the code block by default, but do respect ranges.
99+
100+
```js
101+
console.log('Hello'); // [!code --:2]
102+
console.log('World');
103+
// [!code ++]
104+
console.log('Hello World');
105+
```
106+
107+
```js
108+
// ...
109+
// [!code focus:2] [!code word:log:1]
110+
console.log('Hello World!'); // this instance of "log" is highlighted
111+
console.log('Foobar'); // this one is not
112+
// ...
113+
```
114+
115+
When introducing new functions in a paragraph, consider highlighting them in the following code snippet to draw additional attention to their use. For example, if you just described the `log` function:
116+
117+
```js
118+
console.log('Hello World'); // [!code word:log]
119+
```
120+
121+
Make sure to denote the file names or paths if you describe progress in a specific code sample. When descrbing multiple files, use [tab groups](https://fumadocs.dev/docs/ui/markdown#tab-groups).
122+
123+
````md
124+
```json title="package.json" tab="Configuration"
125+
{ ... }
126+
```
127+
128+
```js tab="Usage"
129+
// code showing how to use what is being configued
130+
```
131+
````
132+
133+
### Directory Structure
134+
135+
You can use the [Files](https://fumadocs.dev/docs/ui/components/files) component to visualize the expected directory structure, if it is relevant to the approach you describe.

apps/guide/README.md

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@
1919
- [Website][website] ([source][website-source])
2020
- [Documentation][documentation]
2121
- [Guide][guide] ([source][guide-source])
22-
Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.
2322
- [discord.js Discord server][discord]
24-
- [Discord API Discord server][discord-api]
2523
- [GitHub][source]
26-
- [Related libraries][related-libs]
2724

2825
## Contributing
2926

30-
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
31-
[documentation][documentation].
32-
See [the contribution guide][contributing] if you'd like to submit a PR.
27+
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the existing guide.
28+
See [the contribution guide][./contributing] if you'd like to submit a PR.
29+
30+
## Local Development
31+
32+
To install and run just the guide portion of the repository for development, you can install dependencies with `pnpm --filter guide install` and serve a development version of the guide on localhost with `pnpm dev`.
3333

3434
## Help
3535

@@ -38,11 +38,9 @@ If you don't understand something in the documentation, you are experiencing pro
3838
[website]: https://discord.js.org
3939
[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website
4040
[documentation]: https://discord.js.org/docs
41-
[guide]: https://discordjs.guide/
42-
[guide-source]: https://github.com/discordjs/guide
41+
[guide]: https://discord.js/guide
42+
[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide
4343
[guide-update]: https://discordjs.guide/additional-info/changes-in-v14.html
4444
[discord]: https://discord.gg/djs
45-
[discord-api]: https://discord.gg/discord-api
46-
[source]: https://github.com/discordjs/discord.js/tree/main/apps/website
47-
[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries
45+
[source]: https://github.com/discordjs/discord.js/tree/main/apps/guide
4846
[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md

apps/guide/content/docs/index.mdx

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
---
2+
title: Cooldowns
3+
---
4+
5+
Spam is something you generally want to avoid, especially if one of your commands require calls to other APIs or takes a bit of time to build/send.
6+
7+
<Callout>
8+
This section assumes you followed the [Command Handling](../app-creation/handling-commands) part of the guide.
9+
</Callout>
10+
11+
First, add a cooldown property to your command. This will determine how long the user would have to wait (in seconds) before using the command again.
12+
13+
```js title="commands/utility/ping.js"
14+
const { SlashCommandBuilder } = require('discord.js');
15+
16+
module.exports = {
17+
cooldown: 5, // [!code ++]
18+
data: new SlashCommandBuilder().setName('ping').setDescription('Replies with Pong!'),
19+
async execute(interaction) {
20+
// ...
21+
},
22+
};
23+
```
24+
25+
In your main file, initialize a [Collection](../additional-info/collections) to store cooldowns of commands:
26+
27+
```js
28+
client.cooldowns = new Collection();
29+
```
30+
31+
The key will be the command names, and the values will be Collections associating the user's id (key) to the last time (value) this user used this command. Overall the logical path to get a user's last usage of a command will be `cooldowns > command > user > timestamp`.
32+
33+
In your `InteractionCreate` event handler, add the following code:
34+
35+
```js title="index.js / interactionCreate.js (if you followed the event handler section)"
36+
// ...
37+
// [!code ++:14]
38+
const { cooldowns } = interaction.client;
39+
40+
if (!cooldowns.has(command.data.name)) {
41+
cooldowns.set(command.data.name, new Collection());
42+
}
43+
44+
const now = Date.now();
45+
const timestamps = cooldowns.get(command.data.name);
46+
const defaultCooldownDuration = 3;
47+
const cooldownAmount = (command.cooldown ?? defaultCooldownDuration) * 1_000;
48+
49+
if (timestamps.has(interaction.user.id)) {
50+
// ...
51+
}
52+
```
53+
54+
You check if the `cooldowns` Collection already has an entry for the command being used. If this is not the case, you can add a new entry, where the value is initialized as an empty Collection. Next, create the following variables:
55+
56+
1. `now`: The current timestamp.
57+
2. `timestamps`: A reference to the Collection of user ids and timestamp key/value pairs for the triggered command.
58+
3. `cooldownAmount`: The specified cooldown for the command, converted to milliseconds for straightforward calculation. If none is specified, this defaults to three seconds.
59+
60+
If the user has already used this command in this session, get the timestamp, calculate the expiration time, and inform the user of the amount of time they need to wait before using this command again. Note the use of the `return` statement here, causing the code below this snippet to execute only if the user has not used this command in this session or the wait has already expired.
61+
62+
Continuing with your current setup, this is the complete `if` statement:
63+
64+
```js title="index.js / interactionCreate.js (if you followed the event handler section)"
65+
const defaultCooldownDuration = 3;
66+
const cooldownAmount = (command.cooldown ?? defaultCooldownDuration) * 1_000;
67+
68+
// [!code focus:13]
69+
if (timestamps.has(interaction.user.id)) {
70+
// ... // [!code --]
71+
// [!code ++:9]
72+
const expirationTime = timestamps.get(interaction.user.id) + cooldownAmount;
73+
74+
if (now < expirationTime) {
75+
const expiredTimestamp = Math.round(expirationTime / 1_000);
76+
return interaction.reply({
77+
content: `Please wait, you are on a cooldown for \`${command.data.name}\`. You can use it again <t:${expiredTimestamp}:R>.`,
78+
flags: MessageFlags.Ephemeral,
79+
});
80+
}
81+
}
82+
```
83+
84+
Since the `timestamps` Collection has the user's id as the key, you can use the `get()` method on it to get the value and sum it up with the `cooldownAmount` variable to get the correct expiration timestamp and further check to see if it's expired or not.
85+
86+
The previous user check serves as a precaution in case the user leaves the guild. You can now use the `setTimeout` method, which will allow you to execute a function after a specified amount of time and remove the timeout.
87+
88+
```js
89+
// [!code focus]
90+
if (timestamps.has(interaction.user.id)) {
91+
const expiredTimestamp = Math.round(expirationTime / 1_000);
92+
return interaction.reply({
93+
content: `Please wait, you are on a cooldown for \`${command.data.name}\`. You can use it again <t:${expiredTimestamp}:R>.`,
94+
flags: MessageFlags.Ephemeral,
95+
});
96+
} // [!code focus]
97+
98+
// [!code ++:2] [!code focus:2]
99+
timestamps.set(interaction.user.id, now);
100+
setTimeout(() => timestamps.delete(interaction.user.id), cooldownAmount);
101+
```
102+
103+
This line causes the entry for the user under the specified command to be deleted after the command's cooldown time has expired for them.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
title: Reloading Commands
3+
---
4+
5+
When writing your commands, you may find it tedious to restart your bot every time for testing the smallest changes. With a command handler, you can eliminate this issue and reload your commands while your bot is running.
6+
7+
<Callout>
8+
ESM does not support require and clearing import cache. You can use [hot-esm](https://www.npmjs.com/package/hot-esm)
9+
to import files without cache. Windows support is experimental per [this
10+
issue](https://github.com/vinsonchuong/hot-esm/issues/33).
11+
</Callout>
12+
13+
<Callout>
14+
This section assumes you followed the [Command Handling](../app-creation/handling-commands) part of the guide.
15+
</Callout>
16+
17+
```js title="commands/utility/reload.js"
18+
const { SlashCommandBuilder } = require('discord.js');
19+
20+
module.exports = {
21+
data: new SlashCommandBuilder()
22+
.setName('reload')
23+
.setDescription('Reloads a command.')
24+
.addStringOption((option) => option.setName('command').setDescription('The command to reload.').setRequired(true)),
25+
async execute(interaction) {
26+
// ...
27+
},
28+
};
29+
```
30+
31+
First off, you need to check if the command you want to reload exists. You can do this check similarly to getting a command.
32+
33+
```js
34+
module.exports = {
35+
// ...
36+
// [!code focus:10]
37+
async execute(interaction) {
38+
// ... // [!code --]
39+
// [!code ++:6]
40+
const commandName = interaction.options.getString('command', true).toLowerCase();
41+
const command = interaction.client.commands.get(commandName);
42+
43+
if (!command) {
44+
return interaction.reply(`There is no command with name \`${commandName}\`!`);
45+
}
46+
},
47+
};
48+
```
49+
50+
<Callout type="warn">
51+
The reload command ideally should not be used by every user. You should deploy it as a guild command in a private
52+
guild.
53+
</Callout>
54+
55+
To build the correct file path, you will need the file name. You can use `command.data.name` for doing that.
56+
57+
In theory, all there is to do is delete the previous command from `client.commands` and require the file again. In practice, you cannot do this easily as `require()` caches the file. If you were to require it again, you would load the previously cached file without any changes. You first need to delete the file from `require.cache`, and only then should you require and set the command file to `client.commands`:
58+
59+
```js
60+
delete require.cache[require.resolve(`./${command.data.name}.js`)];
61+
62+
try {
63+
const newCommand = require(`./${command.data.name}.js`);
64+
interaction.client.commands.set(newCommand.data.name, newCommand);
65+
await interaction.reply(`Command \`${newCommand.data.name}\` was reloaded!`);
66+
} catch (error) {
67+
console.error(error);
68+
await interaction.reply(
69+
`There was an error while reloading a command \`${command.data.name}\`:\n\`${error.message}\``,
70+
);
71+
}
72+
```
73+
74+
The snippet above uses a `try...catch` block to load the command file and add it to `client.commands`. In case of an error, it will log the full error to the console and notify the user about it with the error's message component `error.message`. Note that you never actually delete the command from the commands Collection and instead overwrite it. This behavior prevents you from deleting a command and ending up with no command at all after a failed `require()` call, as each use of the reload command checks that Collection again.

0 commit comments

Comments
 (0)