前端:React + 一层很薄的 fetch · znzryb
## 技术栈
前端在 `frontend/`:**React 19 + TypeScript + Vite**,路由用 `react-router-dom`。代码编辑器是 Monaco(就是 VS Code 那个编辑器),Markdown 用 `react-markdown` 渲染,公式用 KaTeX。
## 调接口:一层很薄的 fetch
前端没有用 axios,也没有 React Query 这类数据层库。所有接口都走 `frontend/src/api/http.ts` 里的一个函数:
```ts
export async function request<T>(method: string, path: string, body?: unknown): Promise<T> {
const resp = await fetch(path, { method, headers: ..., body: JSON.stringify(body) });
const json = await resp.json().catch(() => null);
if (!resp.ok) throw new ApiError(resp.status, json?.error?.code, json?.error?.message, ...);
return json as T;
}
```
然后 `frontend/src/api/client.ts` 把每个接口包成一个有类型的函数,比如:
```ts
api.blog.post(username, slug) // GET /api/users/{username}/blog/{slug}
api.blog.read(username, slug) // POST …/read:报一次「读过这篇」
```
接口返回什么形状,在 `client.ts` 里用 TypeScript 的 `interface` 写死。**前后端的约定以 `docs/api-contract.md` 为准**:改接口先改这份文档,再改两边的代码。
## 开发时怎么连后端
本地开发时 Vite 跑在 5173 端口,`vite.config.ts` 里配了代理:凡是 `/api` 开头的请求转给 `http://localhost:8080`。所以前端代码里写的永远是相对路径 `/api/...`,开发时走 Vite 代理,上线后走 nginx,代码一个字不用改。
## 页面放在哪
| 目录 | 放什么 |
|---|---|
| `frontend/src/pages/` | 一个路由一个页面,比如 `ChapterPage.tsx`(章节 / 博客小节页)、`TopicPage.tsx`(专题 / 博客文章页) |
| `frontend/src/components/` | 多个页面共用的组件 |
| `frontend/src/App.tsx` | 路由表:哪个地址显示哪个页面 |
| `frontend/tests/` | Vitest 单测,接口用 msw 模拟 |
前端的 `App.tsx` 和后端的 `app.go` 是一对:一个管「地址 → 页面」,一个管「接口路径 → handler」。