实践: 使用 Hono 开发全栈应用
本文最后更新于:2025年8月7日 凌晨
场景
最近写了几个前后端都包含的应用,从最初的 Next.js 到后来的 SvelteKit,再到 Tanstack Router,终究不如熟悉的 Hono 框架那么好使。所有的 Web 元框架都在尝试将服务端加入到框架中,但没有一个做的足够好。例如 Cloudflare 上包含许多官方服务,作为一个服务端框架,Hono 的集成做的很棒,但 Web 元框架并非如此。
为什么使用 Hono
为什么 Web 元框架已经有服务端路由了,还要使用 Hono 呢?有几个原因
- 抽象不一:每个元框架都有不同的语法和规则,例如 Next.js Server Components [1]、SvelteKit Server routing [2]、或者 TanStack Server Functions [3]。
- 功能残缺:处理简单的 JSON API?没问题。复杂的 API 结合 Cloudflare 多个服务?很困难。
- 尺寸很大:元框架的 bundle size 非常庞大,即便以小巧著称的 SvelteKit 也有 132kb,而 Hono 构建后只有 18kb.
抽象不一
不管使用什么 Web 框架,Hono 的知识都是通用的。可以轻松的将 Hono 应用部署到任何地方,例如 Cloudflare、Vercel、Deno 等。而 Web 元框架。。。好吧,最好的说法是百花齐放。看几个例子
Next.js 声称在 React 组件中直接耦合数据库查询推荐的做法。
PHP:敢问今夕是何年?
1 |
|
好吧,其实它也有 Route Handlers,像是下面这样。是的,需要 export 不同的函数来处理不同的请求,而路径则取决于文件相对路径。想要快速搜索特定路径的 API?抱歉,你需要在文件系统中找找看。
1 |
|
SvelteKit 也是类似的。
1 |
|
Tanstack 据称从 tRPC 得到了灵感,嗯。。。
1 |
|
好吧,它们有什么共通之处?嗯,显然基本概念是类似的,但除此之外?生态系统全部没有共享,想要连接 KV?数据库?OAuth2 登录?抱歉,你需要找到适合 Web 元框架的方法。
功能残缺
而且对于 Cloudflare 来说,Hono 的集成度相当高,包括 KV/D1、R2、Pages 等。而且对于其他服务端需要的功能,例如数据库、登录、OAuth2 以及测试集成都做的非常棒。
- 数据库:对 D1/Postgresql 支持的都很好(不过推荐使用 Drizzle 而非 Prisma)[4]
- 登录:支持 JWT 中间件,使用起来非常简单 [5]
- OAuth2: 官方的 OAuth Providers [6] 比 Auth.js 和 Better Auth 更简单,也更容易理解和调试,它的黑盒部分较少,不关心数据如何存储
- 测试:全面拥抱 vitest [7],某知名框架至今仍然优先支持 jest
尺寸很大
这是一个直观的对比,可以明显看到不管是构建时间还是最终 bundle 产物的大小差异都非常明显。
SvelteKit minimal
Hono starter
实现
谁在前面?
现在,同时使用 Hono 和 Web 元框架,例如 SvelteKit,来开发一个应用。问题来了,谁在前面?也就是说,Hono 在前面并转发路由,还是 SvelteKit 在前面并转发路由?由于下面几个特征,Hono 在前面会更好
- Hono 的代码更少,启动更快
- 元框架可能会有一些意外的行为,例如自动序列化所有 Response [8]
- 如果没有 SSR(例如 SPA/SSG),那么元框架根本不会有服务端代码
Hono 作为入口
现在,终于到了实现的部分,下面是 Hono 作为入口,静态资源转发到 SvelteKit 的静态产物。最终部署到 Cloudflare Workers 上。
首先确定静态资源在哪儿,例如在 SvelteKit 中,它是由 @sveltejs/adapter-cloudflare
插件配置的。例如下面配置的是 dist 目录。
1 |
|
然后需要配置 wrangler.json 来将静态资源绑定到 ASSETS 上。例如下面配置的是 dist 目录。
1 |
|
最后在 hono 的入口文件中将找不到的路由全部转发到 SvelteKit 的静态资源就好了。
1 |
|
现在,就可以在编码时服务端使用 Hono 而客户端使用喜欢的 Web 元框架了。
1 |
|
缺点
说了这么多,这种模式的缺点是什么?
- Hono 在前面时如果 SSR 需要调用服务端 API,不能在内部转换为函数调用,而是必须经过外部绕一圈请求回来。
- 没有 Web 元框架提供的类型安全,当然这是一个可以解决的问题,例如 Trpc 或 OpenAPI 等。
- 一般需要拆分为 monorepo 多模块,即 packages/server 和 packages/client,可能会增加一些复杂性
- 如果仍然需要 SSR,那么还需要在 Hono 中拦截 404 请求并调用 Web 元框架构建出来的 server/index.js 动态执行
总结
Web 全栈开发是一个流行的趋势,将 Web 的前端/服务端放在一起写看起来很有吸引力,但最终可能在一如既往的绕远路,就像 Next.js 终究活成了一个怪物。另外对于不需要动态渲染 UGC [9] 的网站而言,SSR 通常增加的复杂性可能是没有必要的。
- https://nextjs.org/docs/app/getting-started/fetching-data#with-an-orm-or-database ↩
- https://svelte.dev/docs/kit/routing#server ↩
- https://tanstack.com/start/latest/docs/framework/react/server-functions ↩
- https://hono.dev/examples/prisma#d1-database ↩
- https://hono.dev/docs/middleware/builtin/jwt ↩
- https://github.com/honojs/middleware/tree/main/packages/oauth-providers ↩
- https://hono.dev/docs/guides/testing ↩
- https://github.com/sveltejs/kit/issues/9401 ↩
- https://en.wikipedia.org/wiki/User-generated_content ↩