Build a Discord bot using JavaScript!
To keep things tidy here, if you have never setup a Discord bot before, follow this guide for the first half.
When you get to setting up the Initial Files section stop there and continue from this point on.
Once you have you bot application setup and token at the ready, we can begin!
Initial Files
Create the home directory where all the files for the bot to run will live.
Get started with the following commands:
npm init
Follow each prompt and complete.npm install discord.js discord-api-types dotenv
npm install nodemon -D
Now in the package.json
file have a "start" and "server" under the script object. This is just a snippet of what should be in the file, but there should be more.
"main": "index.js",
"scipts": {
"start": "node .",
"server": "nodemon ."
}
The,"main", in this case will be the file that starts the bot where the bulk of the code will go. Later, we will refactor to have it looking clean.
touch index.js
touch .env
.gitignore
To establish as a git repo run git init
.gitignore
In the .gitignore
file place:
- node_modules
- .env
- config.json
.env
In .env
is where the bot token will go
- TOKEN=
index.js
// './index.js'
const { Client, Intents } = require('discord.js')
require('dotenv').config()
// Create a new client instance
const client = new Client({
intents: [Intents.FLAG.GUILDS, Intents.FLAHS.GUILD_MESSAGES],
})
// When the client is ready, run this code only once
client.once('ready', () => {
console.log(`Logged in as ${client.user.tag}`)
})
// Login to Discord with your client's token
client.login(process.env.TOKEN)
Test the bot
Running the bot through node
directly or using one of the scripts that we wrote earlier to get the bot online.
npm start
or npm server
Alternatively, you can run the scripts manually by node index.js
.
control + c
to kill the bot to add more code.
Do some stuff
Within the index.js
file we'll have the bot respond to messages with a message and be able to get a random quote.
// './index.js'
// require 'node-fetch'
const fetch = require('node-fetch')
...
// Get random quote
function getQuote() {
return fetch('https://zenquotes.io/api/random')
.then((res) => {
return res.json()
})
.then((data) => {
return data[0]['q'] + ' -' + data[0]['a']
})
}
// Respond to message
client.on('messageCreate', (msg) => {
// Do not allow a bot to reply to this
if (msg.author.bot) return
// Switch statement to check for incoming messages that match
switch (msg.content) {
case 'hello':
msg.channel.send(`Hello ${msg.author.username}`)
break
case 'ping':
msg
.reply('pong')
.then((msg) => {
setTimeout(() => msg.delete(), 5000)
})
.then(console.log('We just got pinged!!!'))
break
case '$inspire':
getQuote().then((quote) => msg.channel.send(quote))
break
default:
break
}
})
...
Make sure to have the break
in each case otherwise the bot will run through the statement and the output will not make sense as it will return everything in the switch.
Also the "inspire" message with the "$" will act as a pseudo-command in this case if you are wanting to avoid some words from being checked.
Refactor Time
The index.js
is pretty cluttered now so time for some clean up. This practice will help maintain the understanding of how the bot should be acting rather than needing to scope through the entire file for a some problem that may have occurred.
index.js
// './index.js'
// add external file
const listener = require('./listener')
...
// After "client.once"
// Respond to message (refactored)
client.on('messageCreate', (message) => {
listener.onMessage(message)
})
...
listener.js
-
touch listener.js
// './listener.js'
const Functions = require('./Functions')
function onMessage(message, client) {
// Ignore other bots
if (message.author.bot) return
message.content = message.content.toLowerCase()
switch (message.content) {
case 'hello':
message.channel.send(`Hello ${message.author.username}`)
break
case 'ping':
message
.reply(Functions.getPing(message))
.then((message) => {
setTimeout(() => message.delete(), 5000)
})
.then(console.log('We just got pinged!!!'))
break
case '$inspire':
Functions.getQuote().then((quote) => message.channel.send(quote))
break
default:
break
}
}
module.exports = { onMessage }
We have moved the messageCreate listener to a new file and will be called and return when matching a single message.
Functions.js
-
touch Functions.js
// Require 'node-fetch' for quotes
const fetch = require('node-fetch')
// Get random quote
function getQuote() {
return fetch('https://zenquotes.io/api/random')
.then((res) => {
return res.json()
})
.then((data) => {
return data[0]['q'] + ' -' + data[0]['a']
})
}
function getPing(message) {
let latency = `Latency is ${message.createdTimestamp - Date.now()}ms.`
console.log(`Latency is ${message.createdTimestamp - Date.now()}ms.`)
return latency
}
module.exports = {
getQuote,
getPing,
}
My main purpose with Functions.js
is to add random functions/methods for a localized place to test other functionality.
Later on I may add slash commands for the bot to perform actions and be able to show a context menu for commands that a user will have access to per access level/guild.
Until then the bot will remain a backend handler for server management for use on select Discord servers.
Top comments (0)