Hono 前后端分离系列 02:项目结构和本地开发环境
前后端分离项目一开始最容易被低估的事情,是目录结构。
很多人觉得目录只是文件怎么摆。
不是。
目录结构其实是在告诉团队:
1 | 什么代码属于前端 |
Hono 很轻,所以它不会强迫你使用某一种工程结构。自由是好事,但自由也意味着你要提前做一些约定。
这篇文章讲一个适合中小型项目的 Hono 前后端分离结构,并把本地开发环境跑起来。
一、先选单仓库还是双仓库
前后端分离有两种常见组织方式。
第一种是双仓库:
1 | my-web |
优点是边界清楚,部署独立,权限也容易分开。
缺点是共享类型和联调会麻烦一些。比如后端改了接口返回结构,前端不一定第一时间感知。
第二种是 monorepo:
1 | my-app/ |
优点是类型、常量、工具函数、接口客户端都可以共享。缺点是工程配置稍微复杂一点。
如果你是个人项目、小团队、前后端都用 TypeScript,我更推荐 monorepo。
如果前后端团队完全独立,部署和权限也分开,双仓库更自然。
本文用 monorepo 来讲。
二、推荐目录结构
一个比较干净的起点:
1 | hono-separated-app/ |
这里最重要的是 apps/api。
Hono 后端可以很小,但不要把所有代码都堆进 index.ts。一个文件写到几百行以后,后面一定会痛。
我通常这样拆:
1 | routes 路由入口,只处理 HTTP 层 |
这不是为了显得“架构很高级”。
这是为了让代码在第 20 个接口出现时,还能看懂。
三、创建 workspace
根目录初始化:
1 | mkdir hono-separated-app |
写 pnpm-workspace.yaml:
1 | packages: |
根目录 package.json 可以这样写:
1 | { |
创建目录:
1 | mkdir -p apps/api/src apps/web/src packages/shared/src |
四、创建 Hono API
进入 API 项目:
1 | cd apps/api |
写 apps/api/package.json:
1 | { |
如果你跑在 Node.js,需要用 Node 适配器:
1 | pnpm add @hono/node-server |
写 src/index.ts:
1 | import { serve } from '@hono/node-server' |
Hono 官方文档里也提到,Hono 最初不是为 Node.js 设计的,但通过 Node.js Adapter 可以运行在 Node.js 上。实际生产中,如果你部署到 Cloudflare Workers,则入口会不同。
五、创建 Vite 前端
回到根目录:
1 | cd ../../ |
前端开发时,把 API 地址放到环境变量里。
apps/web/.env.development:
1 | VITE_API_BASE_URL=http://localhost:8787 |
封装一个请求方法:
1 | const API_BASE_URL = import.meta.env.VITE_API_BASE_URL |
页面里调用:
1 | const health = await request<{ ok: boolean; runtime: string }>('/api/health') |
到这里,一个最基础的前后端分离本地开发环境就跑通了。
六、开发时到底要不要用代理
前端联调后端有两种方式。
第一种是直接请求后端完整地址:
1 | http://localhost:8787/api/health |
这样最接近真实跨域场景,可以尽早发现 CORS 问题。
第二种是 Vite 代理:
1 | export default defineConfig({ |
前端只请求:
1 | /api/health |
这样开发体验更顺,但它会把跨域问题藏起来。到了部署环境,如果前端和后端不在同一个域名下,你仍然要正确配置 CORS。
我的建议是:
1 | 本地早期可以用 Vite proxy |
七、先不要急着上复杂工具
很多项目刚开始就引入一堆东西:
1 | ORM |
这些都可能有用,但不是第一天都要上。
前后端分离的第一步应该是:
1 | 项目能启动 |
Hono 很适合这种渐进式开发。
先让 API 层清楚,再逐步加校验、鉴权、数据库、类型安全客户端和部署。