discord.js Guide

repository·main·Indexed 23 days ago

https://github.com/discordjs/guide

An educational resource for developers learning Node.js and Discord bot development. It provides tutorials on bot setup, command organization, database integration using Keyv, and implementing OAuth2 flows including Implicit Grant and Authorization Code Grant.

Tokens
99.1K
Snippets
294
Records
389
Agent score
81%

What's inside discord.js-guide

  1. Getting started with the discord.js guide

    main

    The discord.js guide provides a comprehensive roadmap for building Discord bots. It covers the entire lifecycle of bot development, including:

    • Initial Setup: Getting a bot up and running from scratch.
    • Command Management: Creating, organizing, and expanding command structures (including command handling patterns).
    • Core Features: In-depth explanations for popular topics like reactions, embeds, and canvas.
    • Data Persistence: Working with databases such as sequelize and keyv.
    • Scaling: Implementing sharding for larger bots.
    • Best Practices: Error handling, code cleanliness, and development environment setup.
  2. Introduction to Sequelize ORM

    main

    Sequelize is an Object-Relational-Mapper (ORM) that allows you to interact with various database systems using native JavaScript objects instead of writing raw SQL queries.

    Key benefits include:

    • JavaScript-centric syntax: Write queries that look and feel like native JavaScript.
    • Database Agnosticism: Write code that can run on almost any database system supported by Sequelize, abstracting away the specific nuances and differences between various SQL dialects.
  3. What is a Collection and how does it work?

    main
    A Collection is a utility class in discord.js that extends the native JavaScript Map class. It provides all the standard features of a Map (associating unique keys with values) while adding extra utility methods designed to make common data manipulation tasks easier. Because it extends Map, it is an iterable and can be used in for...of loops or converted to arrays.
  4. Require multiple permissions for a slash command

    main

    To require a user to have multiple permissions to execute a command, you can merge permission flags using the bitwise OR operator (|).

    Note: Discord evaluates against the combined permission bitfield. This means you can require a user to have all of the specified permissions, but you cannot require a user to have any (one of many) of the permissions using this method.

  5. When to use sharding

    main

    Sharding is a technique used to split a bot's process into multiple parallel processes (shards) to maximize efficiency as the bot grows.

    When to shard:

    • Discord requires sharding once your bot reaches 2,500 guilds.
    • It is recommended to begin implementing sharding when your bot approaches 2,000 guilds to ensure a smooth transition.

    Sharding Modes:

    1. ShardingManager (Recommended): Runs shards as separate processes or threads on a single machine. This is the focus of the standard discord.js sharding guide.
    2. Internal Sharding: Creates multiple websocket connections from the same process. This is enabled by passing shards: 'auto' in the ClientOptions of the Client constructor. Note that this is not ideal for large bots due to high memory usage in the single main process.
  6. Transition from message-based to interaction-based command handling

    main

    Modern discord.js development favors interactions over traditional message parsing.

    • Command Handling: Use Slash Commands instead of prefix-based message commands.
    • Event Listeners: Update client.on('message') snippets to use client.on('interactionCreate') to handle slash commands, buttons, and select menus.

    Note on Message Content: Be aware that message content is a privileged intent. If your bot relies on reading message content, you must enable the MessageContent intent in your gateway intents configuration.

  7. How VoiceConnection and AudioPlayer life cycles work

    main

    When using @discordjs/voice, you primarily interact with two stateful components:

    1. VoiceConnection: Maintains the network connection to a Discord voice server.
    2. AudioPlayer: Plays audio resources across a VoiceConnection.

    Because these components are stateful, they progress through various life cycle states. You should subscribe to state changes to handle necessary logic, such as attempting to reconnect a VoiceConnection if it enters the Disconnected state.

  8. Respond to component interactions

    main

    Component interactions (buttons, select menus) must be responded to within 3 seconds. You can use standard slash command response methods like reply(), deferReply(), editReply(), and followUp().

    Additionally, component interactions support two specific methods for managing the message state:

    • update(): Acknowledges the interaction by editing the message the component was attached to. This is preferred over editReply() when you want to change the message content or components. It cannot change the ephemeral state of a message.
    • deferUpdate(): Acknowledges the interaction and resets the message state. This suppresses the need for further immediate responses, though providing feedback via update() or an ephemeral reply() is recommended.

    Once update() or deferUpdate() is called, you can still use followUp() to send new messages or editReply() to make further edits.

  9. How event handling works in discord.js

    main

    discord.js utilizes Node.js's event-driven architecture. The Client class extends Node's EventEmitter, allowing you to register listeners for specific events using .on() (for every occurrence) or .once() (for a single occurrence).

    When an event is emitted, a callback function is executed. Because different events provide different numbers of arguments, it is a common pattern to use the JavaScript rest parameter (...args) to collect all arguments from the event and the spread syntax (...args) to pass them into a custom execute function.

  10. Optimize audio performance with Opus streams

    main

    To reduce CPU usage and jitter, avoid using FFmpeg for audio conversion whenever possible. FFmpeg is triggered when the input type is unknown or when inlineVolume is enabled.

    Optimization Strategies:

    1. Use Opus Formats: Provide audio in .ogg (OggOpus) or .webm (WebmOpus) formats.
    2. Specify StreamType: Explicitly set the inputType in the createAudioResource options to match the format. This allows the library to skip the FFmpeg component of the pipeline.
    3. Avoid Inline Volume: If you use inlineVolume: true, the library must use FFmpeg to handle volume changes, which negates the performance benefit of using Opus streams.
    const { createReadStream } = require('node:fs');
    const { createAudioResource, StreamType } = require('@discordjs/voice');
    
    // High performance: skips FFmpeg
    let resource = createAudioResource(createReadStream('my_file.ogg'), {
    	inputType: StreamType.OggOpus,
    });
    
    resource = createAudioResource(createReadStream('my_file.webm'), {
    	inputType: StreamType.WebmOpus,
    });
  11. Understand Promises and their states

    main

    Promises are used to handle asynchronous tasks in JavaScript (such as discord.js sending requests to the Discord API). A Promise represents an ongoing process and can exist in one of three mutually exclusive states:

    • pending: The process is ongoing and neither resolved nor rejected.
    • resolved: The process completed successfully without errors.
    • rejected: The process encountered an error and could not execute correctly.

    You handle these states using .then() for resolved promises and .catch() for rejected promises.

    function deleteMessages(amount) {
    	return new Promise((resolve, reject) => {
    		if (amount > 10) return reject(new Error('You can\'t delete more than 10 Messages at a time.'));
    		setTimeout(() => resolve('Deleted 10 messages.'), 2_000);
    	});
    }
    
    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
    });