TS App does not attach event listeners once complied, works in dev

Hi, my application doesn't execute any event listeners in a compiled JS state, but works fine when booting into TS via nodemon. I've tried multiple bot accounts with replicated permissions, inside and outside of docker containers, locally and deployed, but for some reason compiling the app to JS gets the app stuck after ApplicationCommandRegistries INFO logs are fired. I also can't amend the LogLevel option on Sapphire instantiation. Any advice or insight greatly welcome! This has been driving me mad
Solution:
For anyone that stumbles upon this in future with similar symptoms (app booting, bot is registered online in discord but events not picked up) my solution was to update package.json's main parameter to an appropriate value against the compiled JS entrypoint - in my case dist/index.js.
Jump to solution
4 Replies
Jimsalad
JimsaladOP•5mo ago
My package.json dependencies and scripts:
"dependencies": {
"@sapphire/framework": "^5.2.1",
"@types/express": "^4.17.21",
"@types/node": "^22.1.0",
"debug": "^4.3.6",
"discord.js": "^14.15.2",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"mysql2": "^3.11.0",
"ts-node": "^10.9.2",
"typescript": "5.4.5",
"winston": "^3.13.1"
},
"scripts": {
"build": "tsc -p .",
"start:dev": "nodemon -L ./src/index.ts"
},
"devDependencies": {
"@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2",
"husky": "^9.1.4",
"nodemon": "^3.1.4"
}
"dependencies": {
"@sapphire/framework": "^5.2.1",
"@types/express": "^4.17.21",
"@types/node": "^22.1.0",
"debug": "^4.3.6",
"discord.js": "^14.15.2",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"mysql2": "^3.11.0",
"ts-node": "^10.9.2",
"typescript": "5.4.5",
"winston": "^3.13.1"
},
"scripts": {
"build": "tsc -p .",
"start:dev": "nodemon -L ./src/index.ts"
},
"devDependencies": {
"@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2",
"husky": "^9.1.4",
"nodemon": "^3.1.4"
}
My tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"moduleResolution": "node",
"baseUrl": "./src",
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
}
}
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"moduleResolution": "node",
"baseUrl": "./src",
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
}
}
Compiled app is started via a node ./index.js command relative to the /dist folder. Dist folder looks like the below once built via Dockerfile
/dist # ls -a
. commands index.js listeners package-lock.json server.js
.. errors lib node_modules package.json
/dist # ls -a
. commands index.js listeners package-lock.json server.js
.. errors lib node_modules package.json
Finally, index.ts looks like this and is the root of my application
import "dotenv/config";
import { SapphireClient, LogLevel } from "@sapphire/framework";
import { GatewayIntentBits } from "discord.js";
import logger from "./lib/logger";
import server from "./server";

const httpPort = 8080;

if (typeof process.env.TOKEN !== "string" || process.env.TOKEN === "") {
throw new Error("TOKEN secret not set");
}

const client = new SapphireClient({
logger: { level: LogLevel.Debug },
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildVoiceStates,
],
loadMessageCommandListeners: true,
});

client.login(process.env.TOKEN);
logger.info("Discord client logged in");

server.listen(httpPort, () => {
logger.info(`App listening on port ${httpPort}`);
});
import "dotenv/config";
import { SapphireClient, LogLevel } from "@sapphire/framework";
import { GatewayIntentBits } from "discord.js";
import logger from "./lib/logger";
import server from "./server";

const httpPort = 8080;

if (typeof process.env.TOKEN !== "string" || process.env.TOKEN === "") {
throw new Error("TOKEN secret not set");
}

const client = new SapphireClient({
logger: { level: LogLevel.Debug },
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildVoiceStates,
],
loadMessageCommandListeners: true,
});

client.login(process.env.TOKEN);
logger.info("Discord client logged in");

server.listen(httpPort, () => {
logger.info(`App listening on port ${httpPort}`);
});
As always, typing the problem out helps you solve it 😅 Thanks for being a rubber duck...
Solution
Jimsalad
Jimsalad•5mo ago
For anyone that stumbles upon this in future with similar symptoms (app booting, bot is registered online in discord but events not picked up) my solution was to update package.json's main parameter to an appropriate value against the compiled JS entrypoint - in my case dist/index.js.
Jimsalad
JimsaladOP•5mo ago
Note this also needs to be relevant to where you're booting from, you can't just specify a folder path and it works it out.
Favna
Favna•5mo ago
Fwiw our guide starts with this because it's such a common problem https://sapphirejs.dev/docs/Guide/getting-started/getting-started-with-sapphire
Sapphire Framework
Getting started with Sapphire | Sapphire
To install Sapphire, you need to install both discord.js and
Want results from more Discord servers?
Add your server