Hono Integration
emroute composes with any HTTP framework that uses Web Standard Request / Response. This guide uses Hono.
Install
bun add hono @emkodev/emroute marked
Markdown renderer
Create a shared renderer used by both server and client. It must handle emroute's fenced block conventions — router-slot (for nested routes) and widget:name (for embedded widgets):
```router-slot
```
renders as <router-slot></router-slot>, and
```widget:counter
{"start": "42"}
```
renders as <widget-counter start="42"></widget-counter>.
See Markdown Renderers for full setup with marked or markdown-it.
Server
// server.ts
import { Hono } from 'hono';
import { Emroute } from '@emkodev/emroute/server';
import { buildClientBundles } from '@emkodev/emroute/server/build';
import { BunFsRuntime } from '@emkodev/emroute/runtime/bun/fs';
import { render } from './renderer.ts';
const appRoot = import.meta.dirname!;
const runtime = new BunFsRuntime(appRoot);
await buildClientBundles({ runtime, root: appRoot, spa: 'root' });
const emroute = await Emroute.create({
spa: 'root',
markdownRenderer: { render },
title: 'emroute + hono',
}, runtime);
const app = new Hono();
// Your API routes — defined before the emroute catch-all
app.get('/api/hello', (c) => c.json({ hello: 'world' }));
// emroute handles everything else
app.all('*', async (c) => {
const response = await emroute.handleRequest(c.req.raw);
if (response) return response;
return c.notFound();
});
export default app;
Key points:
buildClientBundles()producesemroute.js,app.js, andimportmap.jsonfor SPA mode. Call it beforeEmroute.create(). Skip forspa: 'none'.BunFsRuntimeis used here becausebuildClientBundles()callsruntime.transpile(), whichUniversalFsRuntimedoesn't implement.c.req.rawgives Hono's underlying Web APIRequest, which emroute expects.handleRequest()returnsResponse | null— return it when matched, fall through to Hono's 404 whennull.export default app— Bun serves Hono apps via the default export (noBun.serve()needed).- Hono routes defined before the catch-all take priority over emroute routes.
First route
<!-- routes/index.page.md -->
# Hello emroute + Hono
This page is served by emroute through a Hono server.
Run
bun run server.ts
Verify
| Endpoint | Response |
|---|---|
GET / | 302 → /app/ (SPA shell) |
GET /app/ | SPA — client-side routing |
GET /html/ | SSR HTML — markdown rendered to HTML |
GET /md/ | SSR Markdown — raw markdown text |
GET /api/hello | {"hello":"world"} (Hono route) |
All three rendering paths work. Hono routes coexist with emroute routes.
Next: Browser-Only JavaScript