hono-router
v1.3.0
Published
hotloading script to generate file-based routing config for Hono
Readme
hono-router
hono-router is a script that generates a file-based router for Hono, a small, simple, and ultrafast web framework for the Edges. It automatically creates routes based on your file structure and exports, making it easier to organize and maintain your Hono application.
Features
- Automatically generates routes based on your file structure
- Supports dynamic routes (e.g.,
[id].tsbecomes:idin the route) - Supports greedy/catch-all routes (e.g.,
[[blob]].tsfor one or more segments,[...rest].tsfor zero or more) - Allows co-location of component files with routes
- Optional watch mode for automatic regeneration on file changes
- Intelligent route sorting: static paths > dynamic paths > greedy paths
- Supports multiple HTTP methods (GET, PUT, POST, DELETE, PATCH)
- Can be run with Bun for fast execution
Installation
npm install hono-routerUsage
- Create a directory structure for your routes and components. For example:
src/
routes/
index.ts
users/
index.ts
[id].ts
UserList.tsx
posts/
index.ts
[id].ts
PostEditor.tsx
docs/
[...slug].ts # Catch-all route (zero or more segments)
api/
[[...path]].ts # Greedy route (one or more segments)- In your route files, export functions for the HTTP methods you want to handle. For example, in
src/routes/users/[id].ts:
import { Context } from 'hono';
export const onRequestGet = (c: Context) => {
const id = c.req.param('id');
return c.json({ message: `Get user ${id}` });
};
export const onRequestPut = (c: Context) => {
const id = c.req.param('id');
return c.json({ message: `Update user ${id}` });
};- Run the router generator script:
bunx hono-router src/routes router.ts [options]or
npx hono-router src/routes router.ts [options]Options:
--watchor-w: Enable watch mode to automatically regenerate routes on file changes--deno: Generate Deno-compatible imports
This will generate a router.ts file with all your routes.
- In your main Hono app file, import and use the generated router:
import { Hono } from 'hono';
import { loadRoutes } from './router';
const app = new Hono();
loadRoutes(app);
export default app;Component Integration
hono-router allows you to co-locate component files with your routes. Any TypeScript or TypeScript JSX (.tsx) files that start with a capital letter are ignored by the router generation process. This enables you to keep your components close to the routes that use them without affecting the routing logic.
For example:
src/routes/users/UserList.tsxwill be ignored by the routersrc/routes/users/index.tswill be processed for route generation
This feature helps in maintaining a clean and organized project structure where components and their associated routes are kept together.
Watch Mode
To enable watch mode, use the --watch or -w flag when running the script:
npx hono-router src/routes router.ts --watchIn watch mode, the script will continuously monitor your routes directory and automatically regenerate the router file when changes are detected.
Supported HTTP Methods
The generator supports the following HTTP methods:
- GET
- PUT
- POST
- DELETE
- PATCH
- OPTIONS
To use these methods, export functions with the corresponding names in your route files:
onRequestGetonRequestPutonRequestPostonRequestDeleteonRequestPatchonRequestOptions
You can export these as either arrow functions or normal functions:
// Arrow function
export const onRequestGet = (c: Context) => {
return c.json({ message: 'Hello' });
};
// Normal function
export function onRequestGet(c: Context) {
return c.json({ message: 'Hello' });
}Dynamic and Greedy Routes
Dynamic Routes
Standard dynamic routes match a single path segment:
- File:
[id].ts→ Route::id - Example:
/users/[id].tsmatches/users/123but not/users/123/posts
Greedy Routes
Greedy routes can match multiple path segments:
Double-bracket syntax [[param]] (one or more segments)
- File:
[[path]].ts→ Route::path{.+} - Example:
/api/[[path]].tsmatches/api/v1,/api/v1/users, etc. - Does NOT match:
/api(requires at least one segment)
Spread syntax [...param] (zero or more segments)
- File:
[...slug].ts→ Route::slug{.*} - Example:
/docs/[...slug].tsmatches/docs,/docs/intro,/docs/guides/setup, etc.
Route Priority
Routes are automatically sorted to ensure correct matching:
- Static routes (e.g.,
/api/users) - highest priority - Dynamic routes (e.g.,
/api/:id) - medium priority - Greedy routes (e.g.,
/api/:path{.+}) - lowest priority
This ensures that more specific routes are always matched before catch-all routes.
Example Use Cases
API Proxy
// routes/proxy/[[...path]].ts
export const onRequestGet = async (c: Context) => {
const path = c.req.param('path');
// Forward request to backend API
return fetch(`https://backend.api/${path}`);
};Documentation Catch-All
// routes/docs/[...slug].ts
export const onRequestGet = (c: Context) => {
const slug = c.req.param('slug') || 'index';
// Serve documentation page based on slug
return c.html(renderDocsPage(slug));
};Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the ISC License.
