Search code examples
javascriptnode.jsdiscorddiscord.jsfs

How to categorize commands with files in discord.js v13


Question:
Hey guys, I was wondering how I could categorize my commands into files instead of them all being in the commands file. For example the file layout would look something like the following:

discord-bot/
├── node_modules
├── src/
    ├── commands/
        └── Moderation/
            └── command.js
    ├── Data/
        └── config.json
    ├── .env
    └── index.js
├── package-lock.json
└── package.json

My index.js code:

client.once('ready', () => {
    incrementVersionNumber(config.version, ".");

    console.log(`Successfully logged in as ${client.user.tag}`);
    
    // Where the main part of adding the command files begins

    const commands = [];
    const commands_information = new Collection();
    const commandFiles = fs.readdirSync("./src/commands").filter(file => file.endsWith(".js"));

    const clientId = process.env.CLIENTID;

    for(const file of commandFiles){
        const command = require(`./commands/${file}`);
        console.log(`Command loaded: ${command.data.name}`);
        commands.push(command.data.toJSON());
        commands_information.set(command.data.name, command);
    }

    // Where getting the command files ends

    const rest = new REST({ version: '9' }).setToken(token);

    (async () => {
        try {
            console.log('Started refreshing application (/) commands.');
    
            await rest.put(
                Routes.applicationGuildCommands(clientId, 'guildId'),
                { body: commands },
            );
    
            console.log('Successfully reloaded application (/) commands.');
            console.log('-----------------------------------------------');
        } catch (error) {
            console.error(error);
        }
    })();

    client.on('interactionCreate', async interaction => {
        if (!interaction.isCommand()) return;
    
        const { commandName } = interaction;
    
        if (!commands_information.has(commandName)) return;
    
        try {
            await commands_information.get(commandName).execute(client, interaction, config);
        } catch (error) {
            console.error(error);
            await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
        }
    });
});

What I'd like to know:

I know this display is a bit messy but focus on ├── ── commands/, notice how I added another folder and put commands inside of it instead of putting commands inside ├── ── commands/ its self. How can I customize my index.js file to look through every folder in the commands folder, then get every file inside of the category folder? I've attempted to add a * to see if it would grab every folder but it just threw an error saying commands/* was not a directory. So how can I do this? I have also seen this done before so I know it is possible.


Solution

  • I figured it out and was able to solve this by using the following code:

    client.once('ready', () => {
        incrementVersionNumber(config.version, ".");
    
        console.log(`Successfully logged in as ${client.user.tag}`);
    
        client.user.setActivity(`${client.guilds.fetch.length} Servers`, {type: 'WATCHING'});
    
        categories = [
            "Config",
            "Entertainment",
            "Games",
            "Information",
            "Miscellaneous",
            "Moderation",
            "Music",
        ];
    
        const commands = [];
    
        for (var i = 0; i < fs.readdirSync('./src/commands').length - 1; i++) {
            const commands_information = new Collection();
            const commandFiles = fs.readdirSync(`./src/commands/${categories[i]}`).filter(file => file.endsWith(".js"));
    
            for(const file of commandFiles){
                const command = require(`./commands/${categories[i]}/${file}`);
                console.log(`Command loaded: ${command.data.name}`);
                commands.push(command.data.toJSON());
                commands_information.set(command.data.name, command);
        }
        }
    
        const rest = new REST({ version: '9' }).setToken(token);
    
        (async () => {
            try {
                console.log('Started refreshing application (/) commands.');
        
                await rest.put(
                    Routes.applicationGuildCommands(clientId, '910339489770111036'),
                    { body: commands },
                );
        
                console.log('Successfully reloaded application (/) commands.');
                console.log('-----------------------------------------------');
            } catch (error) {
                console.error(error);
            }
        })();
    
        client.on('interactionCreate', async interaction => {
            if (!interaction.isCommand()) return;
        
            const { commandName } = interaction;
        
            if (!commands_information.has(commandName)) return;
        
            try {
                await commands_information.get(commandName).execute(client, interaction, config);
            } catch (error) {
                console.error(error);
                await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
            }
        });
    });