☄️ vth

Backend

Server

Server-side structure and features

Server

The backend is written in Hono, a lightweight and fast web framework.

Why Hono?

Hono is a fast, clean, lightweight and easy to use backend framework. It works great especially in a shared codebase with its type-safe routes and RPC client out of the box.

Hono also provides plugins for Vite, which makes it easy to use with Vite.

How to use it in vth?

The backend in stored in server/index.tsx, it handles both routes and serves client files.

server/index.tsx
/** @jsxImportSource hono/jsx */

import { Hono } from 'hono';
import { serveStatic } from '@hono/node-server/serve-static';
import { rsc } from '~rsc';

const app = new Hono();

const api = new Hono();

app.route('/api', api);

if (import.meta.env.PROD) {
    app.get('/*', serveStatic({ root: './dist/client' }));
}

app.get('/*', (c) => rsc(c.req.raw)); // handling frontend requests

export type App = typeof api; // for hono client

export default app;

This example only serves client files.

Adding routes

The easiest way to add a route is to create a file inside server/routes directory. The file should export a Hono router and be named after the route.

server/routes/example.ts
import { Hono } from 'hono';

export const exampleRouter = new Hono()
    .get('/', (c) => c.text('example route'))
    .post('/', (c) => c.text('example route'));

To insure tRPC works as expected, every route must be defined in a single chain expression.

This approach would break tRPC:

server/routes/example.ts
import { Hono } from 'hono';

const exampleRouter = new Hono()

exampleRouter.get('/', (c) => c.text('example route')); 
exampleRouter.post('/', (c) => c.text('example route')); 

export { exampleRouter };

Now add it to server/index.tsx:

server/index.tsx
import { Hono } from 'hono';
import { exampleRouter } from './routes/example';

const app = new Hono()

const api = new Hono()
    .route('/example', exampleRouter); 

// ...

Learn more

Visit Hono documentation for more information.