文件夹结构

index.ts
import {serve} from '@hono/node-server'
import {Hono} from 'hono'
import * as fs from "node:fs";
import * as path from "node:path";
import {logger} from 'hono/logger'
async function traverseRoutesDir(dirPath: string, handler: (routePath: string) => Promise<void>) {
for (let file of fs.readdirSync(dirPath)) {
const filePath = path.join(dirPath, file);
if (fs.statSync(filePath).isDirectory()) {
await traverseRoutesDir(filePath, handler)
} else {
await handler(filePath)
}
}
}
async function startServer() {
const app = new Hono()
app.use(async (c, next) => {
const url = new URL(c.req.url);
if (!url.pathname.endsWith('/')) {
url.pathname = url.pathname + '/'
return c.redirect(url.href, 308);
}
await next();
});
app.use('*', logger());
const routesPath = path.join(import.meta.dirname, 'routes');
await traverseRoutesDir(routesPath, async (routePath) => {
const url = routePath.replace(routesPath, '').slice(0, 0 - (routePath.split('/').pop() || '').length)
const allowMethods = ["GET", "POST"]
const routeModule = await import(routePath)
for (let method in routeModule) {
if (allowMethods.includes(method)) {
console.log(`${url} - ${method}`);
const handler = routeModule[method] as AsyncGeneratorFunction
(app[method.toLowerCase() as keyof Hono] as Function)(url, handler)
} else {
console.error(`${url} - 不支持${method}方法`)
}
}
})
return app
}
const PORT = 3000
startServer().then((app) => {
console.log(`Server is running on http://localhost:${PORT}`)
serve({
fetch: app.fetch,
port: PORT
})
})
route.ts
import type {Context} from "hono";
export async function GET(c: Context) {
return c.text('Hello Hono!')
}
export async function POST(c: Context) {
return c.text('Hello Hono!')
}