Frontend
Client-side development for Discord Activities
Activity templates use Vite (a fast build tool for web projects) for fast builds and hot module replacement (HMR) — when you save a file, changes appear in your browser immediately without a full page refresh. Frontend code lives in src/app/.
VS Code editor with a Robo.js activity project open, showing Activity.tsx with JSX code and the file explorer displaying src/app, src/api, and config directories
Project Layout
Activity projects organize frontend code into a few key directories:
src/app/App.tsx— Entry point that wraps providers and renders the main component.src/app/Activity.tsx— Main UI component for your activity.src/hooks/— Custom hooks likeuseDiscordSdkfor interacting with the Embedded App SDK.public/— Static assets served at the root path.
Vite Integration
Robo.js integrates Vite as the frontend build tool for activity projects. The configuration file is config/vite.mjs:
import { DiscordProxy } from '@robojs/patch'
import react from '@vitejs/plugin-react-swc'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
react(), // Fast JSX compilation using SWC
DiscordProxy.Vite() // Rewrites network requests to work through Discord's proxy
],
server: {
allowedHosts: true // Allows tunnel URLs to connect to the dev server
}
})import { DiscordProxy } from '@robojs/patch'
import react from '@vitejs/plugin-react-swc'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
react(), // Fast JSX compilation using SWC
DiscordProxy.Vite() // Rewrites network requests to work through Discord's proxy
],
server: {
allowedHosts: true // Allows tunnel URLs to connect to the dev server
}
})Running npx robo dev starts the Vite dev server alongside the Robo backend.
Hot Module Replacement
Changes to files in src/app/ hot reload instantly in the browser. Component state is preserved where possible, so you can iterate on UI without losing context. No manual refresh is needed.
Split view showing code editor on the left with a component being edited and browser on the right reflecting changes instantly through HMR
Styling
CSS files in src/app/ are imported directly in components:
import './App.css'import './App.css'CSS Modules are supported out of the box. Name your file with the .module.css extension and import it as an object:
import styles from './Activity.module.css'import styles from './Activity.module.css'Tailwind CSS integration is available through the react-tailwind-ts template. To add Tailwind to an existing project, follow the Vite guide in the Tailwind CSS docs.
Static Assets
Files placed in the public/ directory are served at the root path. Reference them with absolute paths:
<img src="/rocket.png" alt="Rocket" /><img src="/rocket.png" alt="Rocket" />Store images, fonts, and other static files here.
React vs Vanilla
| React | Vanilla | |
|---|---|---|
| Plugin compatibility | Full (@robojs/sync, etc.) | Limited (some plugins like @robojs/sync require React hooks) |
| Component model | JSX components | Manual DOM |
| Bundle size | Larger | Minimal |
| Template | react-ts (default) | vanilla-ts |
Custom Vite Configuration
Add plugins, aliases, and build options by editing config/vite.mjs. For example, adding a path alias:
import { DiscordProxy } from '@robojs/patch'
import react from '@vitejs/plugin-react-swc'
import { defineConfig } from 'vite'
import path from 'node:path'
export default defineConfig({
plugins: [react(), DiscordProxy.Vite()],
resolve: {
alias: {
'@': path.resolve(__dirname, '../src')
}
},
server: {
allowedHosts: true
}
})import { DiscordProxy } from '@robojs/patch'
import react from '@vitejs/plugin-react-swc'
import { defineConfig } from 'vite'
import path from 'node:path'
export default defineConfig({
plugins: [react(), DiscordProxy.Vite()],
resolve: {
alias: {
'@': path.resolve(__dirname, '../src')
}
},
server: {
allowedHosts: true
}
})DiscordProxy.Vite() must remain in the plugins array for proxy patching to work inside Discord.
