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 <137700126+imnaiyar@users.noreply.github.com>

* chore: fix typos

Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com>

* chore: fix typos

* chore: fix links regarding secret stores across coding platforms

* chore: fix typo

* chore: link node method directly

Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com>

* chore: typos

Co-authored-by: Vlad Frangu <me@vladfrangu.dev>

* chore: typo

Co-authored-by: Vlad Frangu <me@vladfrangu.dev>

* 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 <me@vladfrangu.dev>

* chore: no longer use at-next for pino

---------

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com>
Co-authored-by: Naiyar <137700126+imnaiyar@users.noreply.github.com>
Co-authored-by: Vlad Frangu <me@vladfrangu.dev>
This commit is contained in:
Souji
2025-07-08 15:01:50 +02:00
committed by GitHub
parent ee3ca6f7c6
commit bc6005f446
136 changed files with 11847 additions and 48 deletions

View File

@@ -0,0 +1,99 @@
---
title: Cache Customization
---
Sometimes, you would like to be able to customize discord.js's caching behavior in order to reduce memory usage.
To this end, discord.js provides you with two ways to do so:
1. Limiting the size of caches.
2. Periodically removing old items from caches.
<Callout type="error">
Customization of caching behavior is an advanced topic. It is very easy to introduce errors if your custom cache is
not working as expected.
</Callout>
## Limiting caches
When creating a new `Client`, you can limit the size of caches, which are specific to certain managers, using the `makeCache` option. Generally speaking, almost all your customizations can be done via the helper functions from the `Options` class.
Below is the default settings, which will limit message caches.
```js
const { Client, Options } = require('discord.js');
const client = new Client({
makeCache: Options.cacheWithLimits(Options.DefaultMakeCacheSettings),
});
```
To change the cache behaviors for a type of manager, add it on top of the default settings. For example, you can make caches for reactions limited to 0 items i.e. the client won't cache reactions at all:
```js
const client = new Client({
makeCache: Options.cacheWithLimits({
...Options.DefaultMakeCacheSettings,
ReactionManager: 0,
}),
});
```
<Callout type="error" title="Unsupported customization">
As noted in the documentation, customizing `GuildManager`, `ChannelManager`, `GuildChannelManager`, `RoleManager`, or
`PermissionOverwriteManager` is unsupported! Functionality will break with any kind of customization.
</Callout>
We can further customize this by passing options to `LimitedCollection`, a special kind of collection that limits the number of items. In the example below, the client is configured so that:
1. Only 200 guild members maximum may be cached per `GuildMemberManager` (essentially, per guild).
2. We never remove a member if it is the client. This is especially important, so that the client can function correctly in guilds.
```js
const client = new Client({
makeCache: Options.cacheWithLimits({
...Options.DefaultMakeCacheSettings,
ReactionManager: 0,
GuildMemberManager: {
maxSize: 200,
keepOverLimit: (member) => member.id === member.client.user.id,
},
}),
});
```
## Sweeping caches
In addition to limiting caches, you can also periodically sweep and remove old items from caches. When creating a new `Client`, you can customize the `sweepers` option.
Below is the default settings, which will occasionally sweep threads.
```js
const { Client, Options } = require('discord.js');
const client = new Client({
sweepers: Options.DefaultSweeperSettings,
});
```
To change the sweep behavior, you specify the type of cache to sweep (`SweeperKey`) and the options for sweeping (`SweepOptions`). If the type of cache has a lifetime associated with it, such as invites, messages, or threads, then you can set the `lifetime` option to sweep items older than specified. Otherwise, you can set the `filter` option for any type of cache, which will select the items to sweep.
```js
const client = new Client({
sweepers: {
...Options.DefaultSweeperSettings,
messages: {
interval: 3_600, // Every hour.
lifetime: 1_800, // Remove messages older than 30 minutes.
},
users: {
interval: 3_600, // Every hour.
filter: () => (user) => user.bot && user.id !== user.client.user.id, // Remove all bots.
},
},
});
```
<Callout title="Take some time to consider what you are changing and do some research about what that implies">
Take a look at the documentation for which types of cache you can sweep. Also consider what exactly lifetime implies
for invites, messages, and threads!
</Callout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 719 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,255 @@
---
title: Useful Packages
---
Some of the examples in this section are far from complete. We encourage you to look at the official documentation for all packages you are intending to use in your code. We just want to point out some we found useful in our endeavours of developing Discord apps for years and whet your appetite to try and test some of them in your own code base!
## Day.js
<Callout>Official documentation: [https://day.js.org/](https://day.js.org/en)</Callout>
Day.js is a powerful package that parses, validates, manipulates, and displays dates and times in JavaScript.
It allows you to quickly and easily format dates in any way you want or parse strings back into JavaScript Date objects.
There are many plugins for it that allow you to work with durations and more.
For example if you wanted to ask your users to give you a date,
you can use Day.js to turn it into a Date object you can use in your code:
```js
const input = await interaction.channel.awaitMessages({
filter: (m) => m.author.id === interaction.user.id,
max: 1,
time: 10e3,
errors: ['time'],
});
const date = dayjs(input.first().content).toDate();
```
Using the [duration plugin](https://day.js.org/docs/en/durations/durations), you could tell the user if the date is in the future or the past:
```js
if (date.isValid()) {
const now = dayjs();
const duration = date - now;
const formatted = dayjs.duration(duration, 'ms').format();
if (duration > 0) {
interaction.reply(`The date you gave me is ${formatted} into the future.`);
} else {
interaction.reply(`The date you gave me is ${formatted} into the past.`);
}
} else {
interaction.reply("You didn't give me a valid date.");
}
```
## ms
<Callout>Official documentation: [https://github.com/vercel/ms](https://github.com/vercel/ms)</Callout>
Ms is another tool for working with times in JavaScript. However, ms specializes on durations.
It allows you to convert times in milliseconds into human-readable formats and vice versa.
Example:
```js
await interaction.reply("Send two messages and I'll tell you how far apart you sent them.");
const messages = await interaction.channel.awaitMessages({
filter: (m) => m.author.id === interaction.user.id,
max: 2,
time: 30e3,
errors: ['time'],
});
const difference = messages.last().createdTimestamp - messages.first().createdTimestamp;
const formatted = ms(difference);
await interaction.followUp(`You sent the two messages ${formatted} apart.`);
```
## common-tags
<Callout>
Official documentation: [https://github.com/zspecza/common-tags](https://github.com/zspecza/common-tags)
</Callout>
Common-tags is a library all about working with template literals.
So far, you have probably only used them for interpolating variables into your strings, but they can do a whole lot more.
If you've got time, you should check out [the MDN's documentation about _tagged literals_.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates).
Ever got annoyed your multi-line strings had nasty bits of indentation in them,
but you did not want to remove the indentation in your source code?
common-tags got you covered:
```js
const packageName = 'common-tags';
if (someCondition) {
const poem = stripIndents`
I like ${packageName}.
It makes my strings so pretty,
you should use it too.
`;
console.log(poem);
}
```
This will print your little poem like expected, but it will not have any tabs or other whitespace on the left.
But this is just the start! Another set of useful functions are the list-related functions:
`inlineLists`, `commaLists`, etc.
With those, you can easily interpolate arrays into your strings without them looking ugly:
```js
const options = ['add', 'delete', 'edit'];
// -> Do you want me to add, delete or edit the channel?
interaction.reply(oneLineCommaListsOr`
Do you want me to ${options} the channel?
`);
```
Check the the documentation to find more useful functions.
## chalk
<Callout>Official documentation: [https://www.npmjs.com/package/chalk](https://www.npmjs.com/package/chalk)</Callout>
Chalk is not exactly useful for Discord bots themselves, but it will make your terminal output a lot prettier and organized.
This package lets you color and style your `console.log`s in many different ways; No more simple white on black.
Let's say you want your error messages to be easily visible; Let us give them a nice red color:
```js
console.error(chalk.redBright('FATAL ERROR'), 'Something really bad happened!');
```
![image of code above](./images/chalk-red.png)
You can also chain multiple different multipliers.
If you wanted to have green text, a grey background, and have it all underlined, that is possible:
```js
console.log(chalk.green.bgBrightBlack.underline('This is so pretty.'));
```
![image of code above](./images/chalk-ugly.png)
## pino
<Callout>Official documentation: [getpino.io](https://getpino.io)</Callout>
Pino is a Node.js logger with a very low overhead. But why does that even matter, if `console.log()` exists? Well, `console.log()` is quite slow and not very versatile. Whenever you make a call to `console.log()` your program halts and cannot do anything until the logging is finished.
To get started, install the package:
```sh tab="sh"
npm install pino
npm install -g pino-pretty
```
```sh tab="yarn"
yarn add pino
yarn global add pino-pretty
```
```sh tab="pnpm"
pnpm add pino
pnpm add --global pino-pretty
```
```sh tab="bun"
bun add pino
bun add --global pino-pretty
```
Pino is highly configurable, so we heavily recommend you take a look at their documentation yourself.
To use the same logger across the project you can put the following code into it's own file, for example `logger.js` and import it when needed:
```js
const pino = require('pino');
const logger = pino();
module.exports = logger;
```
```js
const { Client, Events, GatewayIntentBits } = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
const logger = require('./logger');
client.once(Events.ClientReady, () => logger.info('The bot is online'));
client.on(Events.Debug, (info) => logger.debug(info));
client.on(Events.Warn, (info) => logger.warn(info));
client.on(Events.Error, (error) => logger.error(error));
client.login('your-token-goes-here');
```
Pino logs in a json format, so other programs and services like log aggregators can easily parse and work with the output. This is very useful for production systems, but quite tedious to read during development. This is why you installed `pino-pretty` earlier. Instead of formatting the log output itself the developers recommended that you [pipe](<https://en.wikipedia.org/wiki/Pipeline_(Unix)>) the log output to other services instead. `pino-pretty` is a formatter you can use for easy-to-read logs during development.
We recommend you set `pino-pretty` up in a package script in your `package.json` file, rather than typing the pipeline out every time. Please read our [guide section on package scripts](../improving-dev-environment/package-json-scripts), if you are not sure what we're talking about here.
```json
{
"name": "my-bot",
"version": "1.0.0",
"description": "A Discord bot!",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node .",
"lint": "eslint .",
"dev": "node . | pino-pretty -i pid,hostname -t 'yyyy-mm-dd HH:MM:ss'" // [!code ++]
},
"keywords": [],
"author": "",
"license": "ISC"
}
```
<Callout type="warn">
If you are using PowerShell, you have to use a package script for `pino-pretty`. PowerShell handles pipelines in a way
that prevents logging. The command line interface is not affected.
</Callout>
In the example above, further arguments are passed to `pino-pretty` to modify the generated output. `-i pid,hostname` hides these two elements from logged lines and `-t yyyy-mm-dd HH:MM:ss` formats the timestamp into an easy to use format. Try out what works for you! The official [pino-pretty documentation](https://github.com/pinojs/pino-pretty) explains all possible arguments.
To start your bot with prettified input you run the `dev` script via your package manager of choice:
```sh tab="npm"
npm run dev
```
```sh tab="yarn"
yarn run dev
```
```sh tab="pnpm"
pnpm run dev
```
```sh tab="bun"
bun run dev
```
Pino is very flexible, supports custom log levels, worker threads and many more features. Please check out the [official documentation](https://getpino.io) if you want to up your pino game! Below we show an alternative for a production setup. Using this code, you will be logging the raw json objects into a file, instead of printing to your console:
```js
const pino = require('pino');
const transport = pino.transport({
target: 'pino/file',
options: { destination: './log.json' },
});
const logger = pino(transport);
module.exports = logger;
```
## i18next
<Callout>Official documentation: [https://www.i18next.com](https://www.i18next.com)</Callout>
i18next is an internationalization-framework for JavaScript. It is beneficial to translate your bot's user-facing messages into various languages based on the server it is used in.
Covering an entire use case example for internationalization would be out of this guide's scope and requires some more explanation as to how the system operates. Please refer to the official documentation linked above for an in-depth usage guide.