- Removed the `index.html` file as part of the transition to a new routing system. - Updated `package.json` scripts to streamline development commands using `concurrently`. - Enhanced dependency management by adding new packages and updating existing ones in `package.json`. - Introduced a new server function for branding and session management, improving API interactions. - Refactored routing to utilize TanStack Start, ensuring better integration with the existing Dokploy architecture. - Improved static file handling and server response management in the custom Node.js server. - Updated README to reflect changes in architecture and development processes. |
||
|---|---|---|
| .. | ||
| server | ||
| src | ||
| esbuild.config.ts | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
dokploy-vite
TanStack Start migration of the Dokploy dashboard. The Next.js app (apps/dokploy) stays intact; this app reuses all its UI code and its backend logic without duplicating either.
Architecture
Two tiers, one process in production:
- UI tier (TanStack Start): file-based routes in
src/routes/with selective SSR — public pages (login, register, invitation, reset-password) are fully server-rendered (real first paint with content and whitelabel branding), while everything under/dashboardisssr: false(pure client, no SSR cost). The document shell (src/routes/__root.tsx) SSRs per request with whitelabel title/meta/favicon/customCss loaded from the DB via a server function. - API tier (
server/server.ts): Next-free node server owning tRPC, better-auth, OpenAPI REST, deploy/Stripe/git webhooks (reused fromapps/dokploy/pages/apithroughserver/next-compat.ts), websockets, cron jobs and the deployment worker. Start's server functions never import backend code — they call this tier over loopback HTTP (/api/branding,/api/auth/get-session), which keeps the UI dev process free of native/server deps.
Code reuse (unchanged from the SPA phase): @/* aliases into apps/dokploy/* (383 components consumed in place), next/* shims over TanStack Router in src/shims/, @/utils/api re-aliased to a createTRPCReact client with identical hooks/links.
Development
One command (runs both tiers via concurrently):
pnpm --filter dokploy-vite dev
# [api] API + websockets → :3000
# [ui] Start dev (UI + SSR + HMR) → :5173 ← open this one
Or individually: dev:api / dev:ui. The Vite dev server proxies /api and all websocket paths to :3000 (rewriting the origin header so better-auth accepts it). Note: in dev the two tiers are separate processes because Start's dev server owns the Vite process (it's a full SSR runtime, not an embeddable middleware); in production it's a single process (server.ts bridges Start's built handler).
Env loading: the API tier loads apps/vite/.env and falls back to apps/dokploy/.env. The UI tier intentionally reads no env files — its server functions only talk to the API over loopback, and leaking NODE_ENV from a dotfile into vite build produces broken dev-mode SSR bundles (jsxDEV is not a function).
Production — single process, no Next
pnpm --filter dokploy-vite build # Start build → dist/client + dist/server
pnpm --filter dokploy-vite build:server # esbuild → dist-server/*.mjs (server + migration + scripts)
pnpm --filter dokploy-vite start # node server on :3000
server/server.ts serves /api/* + websockets directly, static assets from dist/client, and bridges every other request to Start's built fetch handler (server/start-bridge.ts) for SSR. Docker: Dockerfile.vite at the repo root (image ~1GB vs 4.33GB for the official Next-based image; ~2.6x less memory).
Notes
routeTree.gen.tsis generated by the Start plugin (ignored by biome).- The theme anti-flash script is SSR'd automatically by next-themes — no manual hack.
- Route-level data preload can be added per route with
loader+queryClient.ensureQueryData(framework-native now). - Endgame cleanup (when
apps/dokployis retired): move components in, codemod the 35useRoutercall sites to native TanStack APIs, deletesrc/shims/andserver/next-compat.ts(ideally porting API handlers to Hono routes in the same pass).