How to Fix Stuck Ready Event in Discord Embedded App SDK

If you've been following Discord's Building Your First Activity tutorial, you may have encountered an issue where the Embedded App SDK gets stuck on the READY event. This issue can be caused by a few different things, but the most common cause is Vite's hot module reloading (HMR) feature.

We've seen this issue pop up in a few different places, so we wanted to provide a quick guide on how to fix it. This post will explain it in more detail and suggest ways around it.

TLDR; Quick Fix

If you're in a hurry, the quickest way to fix this without disabling HMR is to make sure you're creating only one instance of the DiscordSDK close to the root of your app. Check out this template to see how it's done.

You can also create a new Discord Activity project with the fix already included by running this in your terminal:

npx create-robo <projectName> -k activity

What's Happening?

When you're developing a Discord Activity with Vite, the hot module reloading feature can cause the SDK to be re-created multiple times. This is because Vite reloads the module when you make changes, which can cause the DiscordSDK to be reinitialized.

Unfortunately, discordSdk.ready() gets stuck on the READY event because Discord sends the payload once per instance. That means your activity will be left waiting for the READY event to fire, but it never will until you restart it.

Starting Fresh with a Fix

To fix this issue, you need to ensure that you're only creating one instance of the DiscordSDK close to the root of your app. This way, the SDK won't be re-initialized every time you make changes, thus you won't need to await discordSdk.ready() more than once.

The easiest and fastest way to prevent this is to make sure you start from a template that already has this fix in place. You can clone this template or create a new project with the fix included by running:

npx create-robo <projectName> -k activity

This will create a new Discord Activity project with the fix already in place, so you won't have to worry about this issue. Check out our guide for more info!

Guide: Creating a Discord Activity in seconds with Robo.js

Fixing Your Existing Project

If you're already working on a project and don't want to start over, you can fix this issue by ensuring that you're only creating one instance of the DiscordSDK close to the root of your app. For example, in a React app, you can use a Context to manage the SDK instance.

Here's a simplified example:

import { DiscordSDK, DiscordSDKMock } from '@discord/embedded-app-sdk'
import { createContext, useContext } from 'react'

export const discordSdk = new DiscordSDK(import.meta.env.VITE_DISCORD_CLIENT_ID)

const DiscordContext = createContext({ discordSdk })

export function DiscordContextProvider(props) {
	const { children } = props
	const setupResult = useDiscordSdkSetup()

	return <DiscordContext.Provider value={setupResult}>{children}</DiscordContext.Provider>
}

export function useDiscordSdk() {
	return useContext(DiscordContext)
}

function useDiscordSdkSetup() {
	// Your setup logic here (e.g., discordSdk.ready() in a useEffect)

	return { discordSdk }
}

Then apply the DiscordContextProvider at the root of your app:

import { DiscordContextProvider } from '../hooks/useDiscordSdk'
import { Activity } from './Activity'
import './App.css'

export default function App() {
	return (
		<DiscordContextProvider>
			<Activity />
		</DiscordContextProvider>
	)
}

This way, Vite won't re-initialize the DiscordSDK every time you make changes, and you won't get stuck on the READY event. It works like so:

  1. The DiscordSDK is created once and passed down through the context.
  2. The SDK is initialized in the context provider.
  3. Components can access the SDK through the custom useDiscordSdk hook.
  4. The same SDK instance will be re-used, as long as you don't edit the useDiscordSdk file.

Conclusion

React's Context is a great way to manage global state in your app, and it's perfect for managing the DiscordSDK instance. By ensuring that you only create one instance of the SDK close to the root of your app, you can prevent the READY event from getting stuck and avoid the need to restart your activity every time you make changes.

We highly recommend using create-robo to create a Discord Activity project. These templates are designed to help you get started quickly and avoid common issues like this one. What's more, they come with a lot of other features and tools to help you build your activity faster and more efficiently, such as Multiplayer Support, TypeScript, Easy Hosting, Streamlined Tunnels, Built-in Database, Plugin System, and so much more!

Don't forget to join our Discord server to chat with other developers, ask questions, and share your projects. We're here to help you build amazing apps with Robo.js! 🚀

🚀 Community: Join our Discord Server

Our very own Robo, Sage, is there to answer any questions about Robo.js, Discord.js, and more