はじめに
完全無料で常時稼働できる Discord Bot の公開先として Deno を試してみたので備忘録を兼ねて記事にまとめてみました。
本記事の内容は2025年2月時点での情報であることに注意してください。
Denoとは
Denoは、JavaScript および TypeScript の実行環境であり、Node.js の開発者である Ryan Dahlによって開発されました。Deno は、Node.js における10個の設計ミスを解決することを目的として開発されました。代表的なものとして以下のような特徴が挙げられます。
- セキュリティ強化:デフォルトでファイル・ネットワーク・環境変数へのアクセスを制限
- TypeScript の標準サポート:追加の設定なしで TypeScript を直接実行可能
- ES モジュールの採用:import を使用し、URL から直接モジュールを取得できる
本記事の構成
本記事では、Discordeno を用いて Discord Bot を開発し、デプロイするまでの手順を解説します。
1. Discord Botの準備
2. Denoをインストールする
3. 設定ファイルの用意
4. オウム返しBot の実装
5. Denoにデプロイする
開発環境
名前 | バージョン |
---|---|
Deno | 2.1.9 |
TypeScripts | 5.6.2 |
Discordeno | 20.0 |
実装
1. Discord Bot の準備
-
デベロッパーアカウントを作成するために以下のサイトにアクセスします
-
Bot の名前を設定し
Create
をクリックします(name
は後から変更可能) -
Bot
タブのTOKEN
にあるReset Token
をクリックするとトークンをコピーできるようになります -
Bot
タブのPrivileged Gateway Intents
のSERVER MEMBERS INTENT
とMESSAGE CONTENT INTENT
にチェックを入れますSERVER MEMBERS INTENT
:Bot がサーバーメンバーの情報(参加・退出・ニックネーム・ロール変更など)をリアルタイムで取得できるようになります。MESSAGE CONTENT INTENT
:Bot がサーバー内のメッセージの内容(テキスト)を読み取れるようになります。 -
OAuth2
タブのOAuth2 URL Generator
にあるScopes
のbot
チェックを入れることで参加させるための認証 URL を発行できます -
発行した URL にアクセスすると管理者権限のあるサーバに追加できるようになります
-
必要に応じたロールを設定します。一般ユーザと同様に Discord 上で設定するか、
OAuth2
タブのBot Permissions
から設定できます。
2. Deno をインストールする
npm がインストールされているという前提で進めます。
npmのインストール確認方法
npm -v
PowerShell を管理者権限で開き以下のコマンドを実行して Deno をインストールします。
iwr https://deno.land/install.ps1 -useb | iex
以下のコマンドでインストールできているか確認します。
deno --version
# deno 2.1.9 (stable, release, x86_64-pc-windows-msvc)
# v8 13.0.245.12-rusty
# typescript 5.6.2
これで Deno のインストールは完了です。
3. 設定ファイルの用意
-
deno.jsonc
というファイルを作成しますdeno.jsonc{ "lock": false, //deno.lock(モジュールのバージョン管理ファイル)を生成しないようにする "tasks": { "start": "deno run -A --watch ./main.ts" // 実行するファイルパス }, "imports": { "$std/": "https://deno.land/std@0.224.0/", "@discordeno/": "https://deno.land/x/discordeno@20.0.0/" // 任意のバージョン } }
-
.evn
というファイルを作成し、Discord Developer Portal のBot
タブに記載されているTOKEN
をコピーして貼り付けます.envTOKEN=Th1si5d1sc0dTok3N
4. オウム返し Bot
ユーザのメッセージをそのまま返すBotを実装します。
import {
createBot,
getBotIdFromToken,
startBot,
Intents,
} from "@discordeno/mod.ts";
import "$std/dotenv/load.ts";
// .env からトークンを取得
const token = Deno.env.get("TOKEN");
const bot = createBot({
token,
botId: BigInt(getBotIdFromToken(token)),
intents: Intents.Guilds | Intents.GuildMessages | Intents.MessageContent,
events: {
// 起動時の処理
ready: (_bot, payload) => {
console.log(`✅ Bot is online!`);
},
// メッセージ受信時の処理
messageCreate: async (bot, message) => {
if (message.authorId === bot.id) return; // ボット自身のメッセージを無視
await bot.helpers.sendMessage(message.channelId, {
content: message.content,
});
},
},
});
// ボットの常時起動
Deno.cron("Continuous Request", "*/3 * * * *", () => {
console.log("🔄 Bot is active!");
});
// ボットを起動
await startBot(bot);
Deno Deploy では、5 分間リクエストがないとスリープ状態になる仕様があります。そこでDeno.cron
を用いてログを出力し、Bot を寝かさないようにします。Deno.cron
は、Deno のスケジュール実行機能で、指定した間隔で定期的に関数を実行するためのものです。今回のコードでは、ボットを 3 分ごとに起動してログを出力する仕組みになっています。
*/3 * * * *
の部分が corn 式で、以下のような構造になっています。
* | * | * | * | * |
---|---|---|---|---|
分 | 時 | 日 | 月 | 曜日 |
0 - 59 | 0 - 23(UTC 時間) | 1 - 31 | 1 - 12 | 0 - 6(日曜 → 土曜) |
注意したいのが、UTC(協定世界時)を用いていることです。UTC = JST - 9時間
と表現されます。現在は UTC に置き換わりつつありますが、GMT と同じ時間を示します。
Bot を起動するには以下のコマンドを実行します。
deno task start
これでテキストチャンネルにメッセージを送信すると Bot が返信してくれます。
5. Deno にデプロイする
-
作成したプログラムを GitHub リポジトリにプッシュしておきます。
トークンなどを記載したファイルは.gitignore に追加しておきましょう。 -
Deno Deployにアクセスし、GitHub と連携する
-
右上の
New Project
をクリックします -
先ほどプッシュしたリポジトリを選択します
-
Project Configuration
でPtoject Name
を設定し、Entrypoint
に実行ファイル名を指定します。すべて設定できたらDeploy Project
をクリックしてデプロイを開始します。 -
トークンを
.env
などで管理しているとトークンを取得できずに以下のようにデプロイに失敗します。そのため Deno 側で環境変数を設定します。画面右上のSettings
をクリックします。 -
Environment Variables
のAdd Variable
をクリックしKEY
に環境変数名、VALUE
に.env
で設定していたトークンを入力します。Save (1 new)
を押して設定完了です。デプロイが成功すれば Bot が常時オンラインになります。
詰まったところ
-
サーバのメンバーをオフラインメンバーも含めて取得
Bot
タブのPrivileged Gateway Intents
で設定できるServer Members Intent
およびPresence Intent
が必要
-
アバター画像の取得
Discord のアバター画像の URL は以下のように管理されています。
https://cdn.discordapp.com/avatars/userId/avatarHash.png
avatarHash
の部分は 16 進数で表現されています。しかし Discordeno のmember.user.avatar
で取得できるものは 10 進数で表現されていました。これを 16 進数に変換、かつ最初の一桁目を落とす必要がありました。`https://cdn.discordapp.com/avatars/${userId}/${member.user.avatar.toString(16).slice(1)}.png`
-
ユーザ-のメインプロフィールの表示名を取得
左のユーザープロフィールの表示名(アドミン)は取得することができませんでした。右のサーバプロフィールのサーバニックネーム(Admin)は
member.nick
で取得でき、自分のアカウントのユーザ名(Adm1n_d4mmyUsern4me)はmember.user.username
で取得できました。
member
オブジェクト、user
オブジェクトを見てみてもglobalName
やdisplayName
などは見つけられず、ユーザの表示名の取得はあきらめました。(どなたか取得方法を知っていたら教えてください;;)member: { id: xxxx, ..., user: { id: xxxx, username: "Adm1n_d4mmyUsern4me", ... }, nick: "Admin", roles: [], ... }
おわりに
今回、Discordeno を使って Discord Bot を作成してみました。体感ですが公式ドキュメントがあまり充実しておらず、分かりづらかったです。また、バージョン間の互換性の問題で正常に動作しないケースも多かったように感じました。しかし、Heroku が有料化した今、無料で常時稼働できる点は Deno の大きな魅力だと思います。Deno の使用感は非常に良かったです。ここまで読んでいただきありがとうございました。
参考にしたサイト等