書くのがめんどくさかったのでAIに任せました。
一応内容はほとんどあってますが自由に開発してください。
後たぶんこの方法じゃ非効率なんでファイル構成とか変えてくれる人募集中です。
このリポジトリでは、src/commands と src/handlers にそれぞれ「スラッシュコマンド」と「ユーザー操作(ボタン / モーダル)」の処理を配置し、src/index.ts が実行時にこれらを自動で読み込みます。
- 実行時に
FILE_TYPEを判定し、.ts(開発)/.js(本番)に合わせて読み込むファイル拡張子を決定します。- 開発:
process.argv[2] !== "js"→FILE_TYPE = ".ts"→BASE_DIR = "./src" - 本番:
process.argv[2] === "js"→FILE_TYPE = ".js"→BASE_DIR = "./dist"
- 開発:
- コマンド読込:
${BASE_DIR}/commands以下のFILE_TYPE拡張子で終わるファイルを全てrequire()して読み込みます。- 読み込んだモジュールは
commands[command.data.name] = commandとして登録されます。
- ハンドラ読込:
${BASE_DIR}/handlersのサブフォルダ(例:button,modal)を列挙し、各フォルダ内のFILE_TYPEで終わるファイルを読み込みます。- 各サブフォルダ名が
actionsオブジェクトのキーとなり、actions[folder][action.data.actionName] = actionと登録されます。
src/
commands/
ping.ts
handlers/
button/
confirm.ts
modal/
sampleModal.ts
types/
command.ts
action.ts
dist/ # ビルド後(.js がここに出力される想定)
プロジェクト内で使われている主要な型定義は src/types/command.ts と src/types/action.ts です。主な要点:
- Command:
data.name,data.description,flags,defer,options?を持つexecute(interaction: CommandInteraction): Promise<void>を実装
- Action:
data.actionNameを持つ(button/modal用に別々の型が定義されています)execute(interaction): Promise<void>を実装
型の詳細については src/types/*.ts を参照してください。
- スラッシュコマンド(
src/commands/ping.ts)の最小例(互換性のために CommonJS スタイルでエクスポートすることを推奨します):
// src/commands/ping.ts
const data = {
name: "ping",
description: "Replies with pong",
flags: 0,
defer: false,
};
async function execute(interaction) {
await interaction.reply("Pong!");
}
module.exports = { data, execute };- ボタンハンドラ(
src/handlers/button/confirm.ts)の例:
// src/handlers/button/confirm.ts
const data = {
actionName: "confirm",
defer: false,
};
async function execute(interaction) {
// ボタン処理
await interaction.reply({ content: "Confirmed!", ephemeral: true });
}
module.exports = { data, execute };- モーダルハンドラ(
src/handlers/modal/sampleModal.ts)の例:
// src/handlers/modal/sampleModal.ts
const data = {
actionName: "sample_modal",
defer: true,
};
async function execute(interaction) {
const value = interaction.fields.getTextInputValue("input-id");
// モーダル処理
await interaction.reply({ content: `You entered: ${value}`, ephemeral: true });
}
module.exports = { data, execute };重要:
src/index.tsはrequire()で読み込んだモジュールのトップレベルにdataとexecuteがあることを期待しています。TypeScript のexport defaultを使う場合、コンパイル後にrequire()するとmodule.defaultに入るケースがあるため、互換性の観点からmodule.exports = { ... }(CommonJS スタイル)を推奨します。
- 開発時に
.tsファイルを直接読み込む場合はts-nodeやts-node/registerを使うか、FILE_TYPEを適切に設定してください。 - 本番ではビルドして
dist(.js)を生成し、node dist/index.js jsのように第2引数にjsを渡して実行することでFILE_TYPE=".js"として読み込みます。
- コマンドが読み込まれない:
commandsフォルダ内のファイルがFILE_TYPEと一致しているか確認(.ts/.js)- モジュールのエクスポート方式が
module.exportsになっているか確認
- ハンドラが登録されない:
handlersのサブフォルダ名(例:button)がactionsのキーとして使われるため、正しいディレクトリ構成か確認
必要であれば、既存の src/commands や src/handlers の中身をもとに、より具体的なテンプレートや lint ルールの提案を書きます。変更してほしい点があれば教えてください。