Command Handler + Full Index.js File Decoded

I have a simple command handler that will work. It does not handle events but it can grab your commands from a separate folder that your bot has. In my example, I have my bot folder and inside that folder I have commands where all of my command files are stored.

I recommend if you are following this tutorial to have your bot set up the same way.

Let’s get started. First, I’m going to show you the code I have all together… this is my index.js file:

const Discord = require('discord.js');
const fs = require('fs');
const client = new Discord.Client();
client.commands = new Discord.Collection();
client.login(token);

const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));

for (const file of commandFiles) {
	console.log(file.slice(0,-3));
	const command = require(`./commands/${file.slice(0,-3)}`)
	client.commands.set(command.name, command);
}

client.on('ready', () => {
        console.log(client.user.tag + ' has logged in!');
)}

client.on('message', message => {
if (!message.content.startsWith(prefix) || message.author.bot) return;

const args = message.content.slice(prefix.length).trim().split(/ +/);
const commandName = args.shift().toLowerCase();

const command = client.commands.get(commandName)
	|| client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));

if (!command) return;

if (!message.guild) return;

if (command.guildOnly && message.channel.type !== 'text') {
	return message.reply('I can\'t execute that command inside DMs!');
}

if (command.args && !args.length) {
	let reply = `You didn't provide any arguments, ${message.author}!`;

	if (command.usage) {
		reply += `\nThe proper usage would be: \`${prefix}${command.name} ${command.usage}\``;
	}

	return message.channel.send(reply);
}

try {
	command.execute(message, args);
} catch (error) {
	console.error(error);
	message.reply('there was an error trying to execute that command!');
}
});

You may see that and be like… what? Don’t worry I am going to explain it. Let’s take this step by step. First part is this:

const Discord = require('discord.js');
const client = new Discord.Client();
client.commands = new Discord.Collection();
client.login(token);

You should remember this from our first tutorial. Skipping past that you have our command handler in all its glory.

const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));

for (const file of commandFiles) {
	console.log(file.slice(0,-3));
	const command = require(`./commands/${file.slice(0,-3)}`)
	client.commands.set(command.name, command);
}

This command handler uses the fs system for Node.js which is built in. So you need to make sure at the top of your file you have the following:

const fs = require('fs');

Without that this command handler will not work. The first line of this command handler is this:

const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));

This is creating a variable called commandFiles that reads the directory commands and finding files that end with .js. The next lines are as follows:

for (const file of commandFiles) {
	console.log(file.slice(0,-3));
	const command = require(`./commands/${file.slice(0,-3)}`)
	client.commands.set(command.name, command);
}

This part is a for function that is finding each file of commandFiles and then for each file, it is spitting it out to the command line with console.log and then it is creating another variable called command and reading all of those files from the commandFiles variable in the commands folder. Then on the last line it is setting those files as commands and reading the ‘names’ from the files and applying those as the command.name.

Now for this to work your command files should look like so:

module.exports = {
     name: 'ping',
     description: 'This displays a ping/pong command in a channel. Checks to see if the bot is alive.',
     aliases: ['beep', 'pong'],
     usage: '!ping',
     execute (message, args) {
       message.channel.send('pong!');
     },
}

This code is exporting all of the files inside the curly braces ({}) so that it can be used by our index.js file.

The rest of this code in the index.js file is the following:

client.on('ready', () => {
        console.log(client.user.tag + ' has logged in!');
}

client.on('message', message => {
if (!message.content.startsWith(prefix) || message.author.bot) return;

const args = message.content.slice(prefix.length).trim().split(/ +/);
const commandName = args.shift().toLowerCase();

const command = client.commands.get(commandName)
	|| client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));

if (!command) return;

if (!message.guild) return;

if (command.guildOnly && message.channel.type !== 'text') {
	return message.reply('I can\'t execute that command inside DMs!');
}

if (command.args && !args.length) {
	let reply = `You didn't provide any arguments, ${message.author}!`;

	if (command.usage) {
		reply += `\nThe proper usage would be: \`${prefix}${command.name} ${command.usage}\``;
	}

	return message.channel.send(reply);
}

try {
	command.execute(message, args);
} catch (error) {
	console.error(error);
	message.reply('there was an error trying to execute that command!');
}
}
});

The ready event (client.on('ready') is the ready event) brings your bot online and spits out to your command line with console.log that your bot is online.

The message event (client.on('message') is the message event) listens to all messages and does something with it. Without this section of your code, your bot will not do anything. It is recommended to only have ONE of these inside your code as having multiples of the message event can cause issues. If you have multiple commands or several things to put inside, just make it longer and longer as we see above.

Now I’m going to go over the following:

if (!message.content.startsWith(prefix) || message.author.bot) return;

const args = message.content.slice(prefix.length).trim().split(/ +/);
const commandName = args.shift().toLowerCase();

const command = client.commands.get(commandName)
	|| client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));

if (!command) return;

if (!message.guild) return;

if (command.guildOnly && message.channel.type !== 'text') {
	return message.reply('I can\'t execute that command inside DMs!');
}

if (command.args && !args.length) {
	let reply = `You didn't provide any arguments, ${message.author}!`;

	if (command.usage) {
		reply += `\nThe proper usage would be: \`${prefix}${command.name} ${command.usage}\``;
	}

	return message.channel.send(reply);
}

try {
	command.execute(message, args);
} catch (error) {
	console.error(error);
	message.reply('there was an error trying to execute that command!');
}
}

The first line: if (!message.content.startsWith(prefix) || message.author.bot) return; listens to see if the message includes your specified prefix OR (|| means or) listens to see if another bot is trying to run a command, if either of these are true, then nothing happens.

The second and third lines:

const args = message.content.slice(prefix.length).trim().split(/ +/);
const commandName = args.shift().toLowerCase();

Makes sure it can read all of your commands, no matter your prefix and makes sure that even if your commands have spaces that they work.
The next lines grab the commands and pull out the aliases and make it so you can use the aliases in place of the command name.

const command = client.commands.get(commandName)
	|| client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));

The next 2 commands don’t do anything if you are not running a command or if the command is being run via DMs.

if (!command) return;

if (!message.guild) return;

The next if function spits out that a message cannot be run via DMs if someone tries to DM the bot.

if (command.guildOnly && message.channel.type !== 'text') {
	return message.reply('I can\'t execute that command inside DMs!');
}

The last if function provides error messages if you do not run commands correctly.

if (command.args && !args.length) {
	let reply = `You didn't provide any arguments, ${message.author}!`;

	if (command.usage) {
		reply += `\nThe proper usage would be: \`${prefix}${command.name} ${command.usage}\``;
	}

	return message.channel.send(reply);
}

The last part of this page is the try/catch function:

try {
	command.execute(message, args);
} catch (error) {
	console.error(error);
	message.reply('there was an error trying to execute that command!');
}

This displays an error in your command line and in the server if there is an error executing/running a command.

There you go! That’s your whole index.js file and command handler! Have fun making your bot from here!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.