Skip to content

Commit da056c0

Browse files
authored
Merge pull request #1 from jzxhuang/next-13-edge-app-router
migrate to Next.js 13
2 parents caf6400 + 4e34e6e commit da056c0

30 files changed

+3062
-1783
lines changed

.env.local.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
# You should copy this file into `.env.local` and fill out the values appropriately
2+
3+
# Settings -> General Information
24
DISCORD_APP_ID=
35
DISCORD_APP_PUBLIC_KEY=
6+
7+
# Settings -> Bot
8+
# Required to register commands, not required to actually run the bot
49
DISCORD_BOT_TOKEN=

.eslintrc.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}

.prettierrc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,9 @@
77
"semi": false,
88
"singleQuote": false,
99
"tabWidth": 2,
10-
"trailingComma": "es5"
10+
"trailingComma": "es5",
11+
"plugins": [
12+
"@ianvs/prettier-plugin-sort-imports",
13+
"prettier-plugin-tailwindcss"
14+
]
1115
}

README.md

Lines changed: 106 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,129 @@
1-
# NextBot: Serverless Discord Bot with Next.js
1+
# NextBot: Next.js Discord Bot Template that runs in the Edge Runtime
22

3-
Serverless Discord bot using Discord's
4-
[slash commands webhook](https://discord.com/developers/docs/interactions/slash-commands#receiving-an-interaction) and
5-
[Next.js](https://nextjs.org/).
3+
NextBot is a template for building and deploying a Discord bot with Next.js. It runs 100% in the edge runtime so you get
4+
lightning-fast responses and zero cold starts. It uses Discord interactions webhooks to receive and reply to commands.
65

76
![Demo GIF](docs/demo.gif)
87

9-
## Try it out
8+
- Runs at the edge: Lightning-fast responses, no cold start.
9+
- Free & easy to deploy: Deploy to Vercel in seconds at no cost. No need to host a server or VM to run your bot! Don't
10+
bother with Heroku, EC2, etc.
11+
- Easy to extend: Since the bot is built on Next.js, you can easily build an accompanying webapp in the same repo.
1012

11-
[![Discord Invite](https://img.shields.io/badge/Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/NmXuqGgkb3)
13+
## Try it out
1214

13-
Join https://discord.gg/NmXuqGgkb3 and use one of the available slash commands.
15+
Join https://discord.gg/NmXuqGgkb3 to try out a demo of NextBot. Type one of these slash commands into the general
16+
channel:
1417

1518
- `/ping`
19+
- `/invite`
1620
- `/randompic`
1721

18-
Or, add NextBot to your own server:
19-
https://discord.com/api/oauth2/authorize?client_id=837427503059435530&permissions=2147483648&scope=bot%20applications.commands
20-
21-
You can also send slash commands through DM the bot once you're in a mutual server with the bot!
22+
Or add NextBot to your own server with this link:
23+
https://discord.com/api/oauth2/authorize?client_id=837427503059435530&permissions=2147485696&scope=bot%20applications.commands
2224

23-
An accompanying static web app also shows the registered commands: https://nextjs-discord-bot.vercel.app/
24-
25-
## Technologies
26-
27-
- Receives slash commands through
28-
[Discord's Interaction webhook](https://discord.com/developers/docs/interactions/slash-commands#receiving-an-interaction),
29-
allowing for a completely serverless approach!
30-
- Built on Next.js: easily build an accompanying dashboard web app in the same repo and call your API directly with SSR!
31-
- Typescript <3 (thanks to https://github.com/discordjs/discord-api-types for Discord types!)
25+
You can also send slash commands through DM to the bot as long as you're in a mutual server with the it!
3226

3327
## Development
3428

35-
Requires a Node.js version that can run Next.js.
29+
Node.js 18+ is required.
3630

3731
### Setup
3832

39-
Follow the one-time setup as follows:
40-
41-
- Clone the repo
42-
- Create a Discord app and bot
43-
- Copy `.env.local.example` into a new file `.env.local` and fill in the blanks with the values from your Discord app
44-
- Register the slash commands. You can learn more about registering commands in the
45-
[Discord API docs](https://discord.com/developers/docs/interactions/slash-commands#registering-a-command). I created
46-
the commands by leveraging `createGlobalCommand` in `services/discord.ts`. I added this to`getServerSideProps` in
47-
`pages/index.tsx` and ran it ONCE (i.e. refresh the page ONCE).
48-
49-
```tsx
50-
await createGlobalCommand({
51-
name: "randompic",
52-
description: "Get a random picture",
53-
options: [
54-
{
55-
name: "type",
56-
description: "What type of picture would you like?",
57-
type: 3,
58-
required: true,
59-
choices: [
60-
{ name: "cat", value: "cat" },
61-
{ name: "dog", value: "dog" },
62-
{ name: "generic", value: "picsum" },
63-
],
64-
},
65-
],
66-
})
67-
68-
await createGlobalCommand({
69-
name: "ping",
70-
description: "Ping pong! I'll respond with pong.",
71-
})
72-
```
73-
74-
You could also make the request via Postman, curl, etc. but I'm lazy
33+
- Clone the repo. This is a
34+
[template repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template)
35+
so you can click the green "Use this template" button on GitHub to create your own repo!
36+
- Run `yarn` to install dependencies.
37+
- [Create a new Discord application](https://discord.com/developers/applications).
38+
- In the `Bot` settings of your Discord application, enable the `Message Content` intent.
39+
- Fill out environment variables:
40+
- In the root of the repository, copy `.env.local.example` into a new file `.env.local`. Fill out the values using the
41+
real values from your Discord app.
42+
- Register some slash commands for your bot. I've included a script to register the commands included in the demo bot.
43+
- Run `yarn register-commands` to execute the script! You only need to run this once, unless you add new commands.
44+
- You can learn more about registering commands in the
45+
[Discord API docs](https://discord.com/developers/docs/interactions/application-commands#create-global-application-command)
7546

7647
### Local Development
7748

78-
- Run `yarn dev`
79-
- Tunnel your localhost:3000 with a tool like [ngrok](https://ngrok.com/). `ngrok http 3000`
80-
- Add the `<YOUR_PUBLIC_TUNNELED_NGROK_URL>/api/interactions` as the `Interactions Endpoint URL` in your Discord app.
81-
- Add the app to a server and slide in its DMs! Your registered slash commands should be available now.
49+
Once you've completed the setup steps above, you're ready to run the bot locally!
50+
51+
Discord can only send events to a public `https` address. You'll need an HTTP tunneling service like
52+
[ngrok](https://ngrok.com/) or [Cloudflare Tunnel](https://www.cloudflare.com/products/tunnel/) when developing locally.
53+
For this guide, I'll be using ngrok.
54+
55+
- Run `yarn dev` to start the Next.js application.
56+
- Assuming you're using ngrok, run `ngrok http 3000` to start your HTTP tunnel.
57+
- In the Discord app settings, set `Interactions Endpoint URL` to `<YOUR_PUBLIC_TUNNELED_NGROK_URL>/api/interactions`.
58+
Make sure to use the `https` URL!
59+
- Save changes in the Discord app settings.
60+
61+
In order to verify your interactions endpoint URL, Discord will send a `PING` message to your bot, and the bot should
62+
reply with a PONG (see `src/pages/api/interactions.ts`). If this is successful, your bot is ready to go!
63+
64+
You can now add your bot to your Discord server and try it out! Use Discord's URL generator in `OAuth2 -> URL Generator`
65+
of your Discord app's settings to generate an invite link. Make sure to select:
66+
67+
- `bot` + `applications.commands` for scopes
68+
- `Send Messages` + `Use Slash Commands` for bot permissions
69+
70+
After adding the bot to a server, try out one of the slash commands like `/ping` or `randompic`!
71+
72+
- You can try modifying the response of the `/ping` command and the changes should be reflected immediately.
73+
- You're ready to add your own commands!
74+
75+
Note: whenever you terminate/restart your ngrok tunnel, you'll need to update the `Interactions Endpoint URL` in the
76+
Discord app settings accordingly.
77+
78+
## Deploy to Production
79+
80+
This project is designed to be deployed on Vercel. I recommend that you create a new Discord Application for production!
81+
Here are some things you should remember to do when deploying:
82+
83+
- Set the environment variables in Vercel accordingly.
84+
- You can still use `yarn register-commands` to register commands for your production bot, as long as you update your
85+
`.env.local` file with the correct values.
86+
- You should set `<YOUR_VERCEL_URL>/api/interactions` as the `Interactions Endpoint URL` in your prod Discord app.
87+
88+
## How It Works
89+
90+
Unlike traditional Discord bots which maintain a persistent connection with Discord (and thus require managing your own
91+
servers), NextBot uses Discord's
92+
[Interactions Endpoint](https://discord.com/developers/docs/interactions/slash-commands#receiving-an-interaction) to
93+
respond to interactions (such as slash commands).
94+
95+
The Interactions Endpoint is now Discord's recommended approach to building bots. If you haven't already, I recommend
96+
you read the [Getting Started](https://discord.com/developers/docs/getting-started) and
97+
[Receiving and Responding](https://discord.com/developers/docs/interactions/receiving-and-responding) pages of Discord's
98+
documentation to learn more about Interactions, Slash Commands, and Discord bots!
99+
100+
And be sure to check out the rest of the Discord docs to see all the awesome stuff you can do aside from basic Slash
101+
commands!
102+
103+
### File Structure
104+
105+
- `src/app/api/interactions/route.ts`: This is the main route handler for the Interactions Endpoint. It receives
106+
interactions from Discord and handles them accordingly.
107+
- `src/discord/verify-incoming-request.ts`: Helper functions to verify incoming requests from Discord, as outlined in https://discord.com/developers/docs/interactions/receiving-and-responding#security-and-authorization.
108+
- `src/app/page.tsx`: A basic web page. This could be your admin portal or whatever you'd like!
109+
110+
## Why Next.js (instead of Express, serverless, or Cloudflare Workers)?
111+
112+
NextBot leverages Next.js 13
113+
[Route Handlers](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) to receive and respond to
114+
interactions. But why Next.js instead of something like Express or serverless (AWS Lambda)?
82115

83-
### Deploy on Vercel
116+
- Next.js is free and effortless to deploy on Vercel. Don't bother with trying to host your Express server
117+
- Compared to serverless, edge is faster (no cold start) and cheaper (Edge Runtimes have more generous free tiers and
118+
are cheaper per request)
84119

85-
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fjzxhuang%2Fnextjs-discord-bot)
120+
A better comparison would be hosting a Discord bot on Cloudflare Workers, as shown in this
121+
[official Discord tutorial](https://discord.com/developers/docs/tutorials/hosting-on-cloudflare-workers). The Next.js
122+
edge runtime is built on Cloudflare Workers! Still, I think Next.js has some notable benefits:
86123

87-
After deploying, add `<YOUR_VERCEL_URL>/api/interactions` as the `Interactions Endpoint URL` in your Discord app.
124+
- Next.js has the advantage of being a full web-app framework, making it easy to build an accompanying web app to go
125+
along with your Discord app!
126+
- Deploying on Vercel is not only simple, but it also scales out very effectively if you need to build a more complex
127+
app (analytics, logging, integrations, etc.)
128+
- You can use Next.js/Vercel features like [Dynamic Image Generation](NextBot is a template for building and deploying a Discord bot with Next.js. It runs 100% in the edge runtime so you get
129+
lightning-fast responses and zero cold starts).

interfaces/discord.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

middlewares/discord-interaction.ts

Lines changed: 0 additions & 72 deletions
This file was deleted.

middlewares/error-handler.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.

next-env.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
/// <reference types="next" />
2-
/// <reference types="next/types/global" />
2+
/// <reference types="next/image-types/global" />
3+
4+
// NOTE: This file should not be edited
5+
// see https://nextjs.org/docs/basic-features/typescript for more information.

next.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/** @type {import('next').NextConfig} */
2+
const nextConfig = {}
3+
4+
module.exports = nextConfig

package.json

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,36 @@
55
"dev": "next",
66
"build": "next build",
77
"start": "next start",
8-
"type-check": "tsc"
8+
"type-check": "tsc",
9+
"register-commands": "tsx ./scripts/register-commands"
910
},
1011
"dependencies": {
11-
"axios": "^0.21.1",
12-
"nanoid": "^3.1.22",
13-
"next": "^10.2.0",
14-
"react": "^17.0.1",
15-
"react-dom": "^17.0.1",
12+
"autoprefixer": "^10.4.16",
13+
"discord-api-types": "^0.37.54",
14+
"dotenv": "^16.3.1",
15+
"ky": "^0.33.3",
16+
"nanoid": "^4.0.2",
17+
"next": "^13.5.2",
18+
"postcss": "^8.4.30",
19+
"react": "^18.2.0",
20+
"react-dom": "^18.2.0",
21+
"tailwindcss": "^3.3.3",
1622
"tweetnacl": "^1.0.3"
1723
},
1824
"devDependencies": {
19-
"@types/node": "^12.12.21",
20-
"@types/react": "^17.0.2",
21-
"@types/react-dom": "^17.0.1",
22-
"discord-api-types": "^0.18.0",
23-
"typescript": "^4.2.4"
25+
"@ianvs/prettier-plugin-sort-imports": "^4.1.0",
26+
"@types/node": "^20.5.1",
27+
"@types/react": "^18.2.20",
28+
"@types/react-dom": "^18.2.7",
29+
"eslint": "^8.47.0",
30+
"eslint-config-next": "^13.4.19",
31+
"prettier": "^3.0.2",
32+
"prettier-plugin-tailwindcss": "^0.5.4",
33+
"tsx": "^3.12.7",
34+
"typescript": "^5.1.6"
2435
},
2536
"license": "MIT",
26-
"description": "Simple discord bot using NextJS and serverless webhook handler for slash commands.",
37+
"description": "Discord bot template using Next.js that runs at the edge. Uses Discord interactions webhooks to receive commands.",
2738
"main": "index.js",
2839
"author": "Jeff Huang"
29-
}
40+
}

0 commit comments

Comments
 (0)