171 lines
8.0 KiB
Markdown
171 lines
8.0 KiB
Markdown
# Cloudflare 部署与性能优化方案(全盘)
|
||||
|
|
|
|||
|
|
> 目标:前端可通过 Cloudflare 域名访问;后端(Supabase / LightRAG / ingest_service / Redis 等)通过 Cloudflare Tunnel 或等价方式对外暴露;同时解决当前“页面切换卡顿”的体感问题,并为后续 OCR(MinerU)与 RAG 自动入库留出扩展空间。
|
|||
|
|
|
|||
|
|
## 0. 现状结论(基于当前代码扫描)
|
|||
|
|
|
|||
|
|
### 0.1 当前代码对 Cloudflare(Edge/Workers/Pages)的直接阻塞点
|
|||
|
|
|
|||
|
|
`wolai-frontend` 内存在大量 Node 内置依赖与本地文件系统读写(`fs/path/process.cwd()`),例如:
|
|||
|
|
|
|||
|
|
- `wolai-frontend/src/lib/mindmap-files.ts`、`wolai-frontend/src/app/api/mindmap/**`:读写 `public/documents` / `public/mindmaps` 下的本地文件
|
|||
|
|
- `wolai-frontend/src/app/api/documents/{create,duplicate,copy-tree}`:本地文件写入/拷贝
|
|||
|
|
- `wolai-frontend/src/lib/ai/onlineAiConfig.ts`:本地读取配置文件
|
|||
|
|
- 部分 API 还使用 `crypto.randomUUID`
|
|||
|
|
|
|||
|
|
这些在 Cloudflare Pages/Workers 的运行时中**不可用或不推荐**(没有传统 Node 文件系统/进程工作目录概念),因此“把整个 Next.js(含 API Routes)直接部署到 Cloudflare 并保持当前行为”会遇到现实阻碍。
|
|||
|
|
|
|||
|
|
### 0.2 当前“页面切换卡”的高概率根因
|
|||
|
|
|
|||
|
|
在改造前,`/documents/[id]` 会把 `documents.content` 作为 Server Component props 直接带到前端编辑器(BlockNote)。当 `content` 较大时,会显著增加:
|
|||
|
|
|
|||
|
|
- 服务器到浏览器的 RSC Flight payload 体积
|
|||
|
|
- 浏览器端 JSON 解析、反序列化与 hydration 负担
|
|||
|
|
|
|||
|
|
这类卡顿会在“切换不同页面”场景中放大。
|
|||
|
|
|
|||
|
|
> 已落地修复:`/documents/[id]` 不再直接携带 `documents.content`,改为客户端按需请求 `/api/documents/content` 后再加载编辑器内容(见下方“P0 优化已实现”)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. Cloudflare 部署拓扑:推荐的三种路径
|
|||
|
|
|
|||
|
|
### 路径 A(推荐优先):Cloudflare 仅做反代/加速,本地跑完整 Next(含 API)
|
|||
|
|
|
|||
|
|
**适用场景**:希望最少改代码、尽快可用;允许前端与 API 都跑在你本地/服务器(Docker),Cloudflare 只提供域名与隧道入口。
|
|||
|
|
|
|||
|
|
- Cloudflare Tunnel 将 `https://你的域名` 指向本地的 `wolai-frontend`(Next server)
|
|||
|
|
- `/api/*` 也由同一 Next server 提供(无需跨域)
|
|||
|
|
- Supabase/LightRAG 等服务同样通过 Tunnel 暴露(可用子域名或路径分流)
|
|||
|
|
|
|||
|
|
**优点**
|
|||
|
|
- 几乎不需要重构(保留 `fs`/本地 mindmap 文件体系)
|
|||
|
|
- cookie / session 同源,前端调用 `/api` 最简单
|
|||
|
|
|
|||
|
|
**缺点**
|
|||
|
|
- 首屏与静态资源仍取决于你本地带宽/延迟(可通过 Cloudflare 缓存静态资源缓解)
|
|||
|
|
- 需要你保证本地服务稳定在线
|
|||
|
|
|
|||
|
|
### 路径 B:Cloudflare 部署“纯静态前端”(SPA/静态 Next),API 全部回源到本地
|
|||
|
|
|
|||
|
|
**适用场景**:希望前端 CDN 化(加载快),后端服务仍由你本地/服务器提供;愿意做一定的前后端解耦与配置改造。
|
|||
|
|
|
|||
|
|
关键改造点:
|
|||
|
|
- 前端不能依赖 Next Server Components 的“服务器取数”,而应改为客户端请求后端 API
|
|||
|
|
- Next 的 `app/api/*` 要迁移到后端服务(或保留在本地 Next,但需要确保 Cloudflare Pages 的 `/api` 反代到本地)
|
|||
|
|
- 所有本地文件读写(mindmap 文件、copy-tree)必须移动到“后端服务”中执行
|
|||
|
|
|
|||
|
|
**优点**
|
|||
|
|
- 前端体验更好(静态资源全球 CDN)
|
|||
|
|
- 后端仍可保留现有 Node 能力(fs、pdf 处理、脚本等)
|
|||
|
|
|
|||
|
|
**缺点**
|
|||
|
|
- 需要统一“API Base URL / 反代规则 / CORS / cookie 域”
|
|||
|
|
- 需要规划“哪些 API 放在本地 Next,哪些独立成后端服务”
|
|||
|
|
|
|||
|
|
### 路径 C:Cloudflare 运行 Next(Workers/Pages Functions)+ 后端回源
|
|||
|
|
|
|||
|
|
**适用场景**:希望尽可能多逻辑在 Cloudflare 边缘,但愿意严格约束 Node 能力,重构较大。
|
|||
|
|
|
|||
|
|
现实结论:以当前代码结构(大量 `fs/path/process.cwd()`)来看,除非先做较大改造,否则不建议直接走该路径。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 性能优化路线图(按优先级)
|
|||
|
|
|
|||
|
|
### P0(已实现,立刻收益):文档内容按需加载,减小路由切换负担
|
|||
|
|
|
|||
|
|
已改动:
|
|||
|
|
- 新增 `GET /api/documents/content?documentId=...`:仅返回 `documents.content`
|
|||
|
|
- `/documents/[id]` 不再 `select content`,避免 RSC 携带大字段
|
|||
|
|
- 编辑器内容在客户端加载:`DocumentContent` 在 `initialContent==null` 时拉取内容并展示“页面内容加载中...”
|
|||
|
|
- `BlockNoteEditor` 在 `normalizedInitialContent` 变化时重新初始化(只会从 `null -> 实际内容` 触发一次)
|
|||
|
|
|
|||
|
|
预期收益:
|
|||
|
|
- 切换页面时,RSC payload 更小、解析更快
|
|||
|
|
- 为 Cloudflare 反代/跨网访问(带宽较差)场景奠定基础
|
|||
|
|
|
|||
|
|
### P1(强烈推荐,低风险高收益):侧边栏与文件树性能
|
|||
|
|
|
|||
|
|
1) 文件树虚拟列表
|
|||
|
|
- `FileTree` 当前对 `rows` 直接 `map` 渲染,文档/附件数量上来后会明显卡顿
|
|||
|
|
- 已有 `@tanstack/react-virtual` 用例(`PrivateTree`),可复用同一技术栈把 `FileTree` 也做虚拟化
|
|||
|
|
|
|||
|
|
2) `assetsByDoc` 构建从 O(n^2) 优化为 O(n)
|
|||
|
|
- 当前实现每次 push 前会 `some()` 去重(n 较大时会变慢)
|
|||
|
|
- 建议改为 `Map<docId, Map<assetKey, asset>>` 一次遍历构建
|
|||
|
|
|
|||
|
|
3) `/api/sidebar` 数据裁剪与拆分
|
|||
|
|
- `fetchSidebarDataset` 对 `media_assets` 使用 `select("*")`,字段过多会拉大 payload
|
|||
|
|
- 建议改为只取侧边栏需要字段;并进一步拆分:
|
|||
|
|
- 文档树(documents)
|
|||
|
|
- 垃圾桶(trashed docs/assets)
|
|||
|
|
- 附件列表(只取当前展开节点/或按 docId 批量懒加载)
|
|||
|
|
|
|||
|
|
### P2(中期):文档内容存储与传输优化(大文档体验)
|
|||
|
|
|
|||
|
|
1) 内容分片/分页加载(可选)
|
|||
|
|
- 对 `documents.content` 进行“块级分页”(例如按顶层 block 分块),在编辑器侧逐步加载
|
|||
|
|
|
|||
|
|
2) 只拉取必要字段
|
|||
|
|
- 页面切换只拉 meta(title/updated_at/options/stats),内容按需加载(已完成)
|
|||
|
|
- backlinks / history 等面板可延迟加载或切换时懒加载
|
|||
|
|
|
|||
|
|
3) 缓存与压缩策略(配合 Cloudflare)
|
|||
|
|
- 对静态资源启用强缓存(Cloudflare 默认可做)
|
|||
|
|
- 对“用户私有”接口设置 `Cache-Control: private`,避免被共享缓存污染
|
|||
|
|
- 对“公开内容(public pages)”可用 `s-maxage` + `stale-while-revalidate`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Cloudflare 反代/穿透下的关键工程点(必须规划)
|
|||
|
|
|
|||
|
|
### 3.1 统一 API 入口与路径分流
|
|||
|
|
|
|||
|
|
建议以同一域名提供:
|
|||
|
|
- `https://mnote.example.com/`:前端
|
|||
|
|
- `https://mnote.example.com/api/*`:后端 API(本地 Next 或独立服务)
|
|||
|
|
- `https://mnote.example.com/supabase/*`:如需(或直接使用 supabase 子域名)
|
|||
|
|
- `https://mnote.example.com/lightrag/*`:LightRAG 7777(建议仅内部/鉴权后暴露)
|
|||
|
|
|
|||
|
|
这样可以最大化减少 CORS 与 cookie 域问题。
|
|||
|
|
|
|||
|
|
### 3.2 上传链路必须“直传”
|
|||
|
|
|
|||
|
|
Cloudflare/反代链路对大文件上传很敏感:
|
|||
|
|
- 建议前端改为“拿签名 URL 后直传到 Supabase Storage”(你已有 `/api/media/signed-url`)
|
|||
|
|
- 避免通过前端服务器中转大文件(会受 CF/反代限制、也会拖慢)
|
|||
|
|
|
|||
|
|
### 3.3 本地文件系统能力的迁移策略
|
|||
|
|
|
|||
|
|
当前 mindmap 文件存储在 `public/documents/**` 本地目录,这对 Cloudflare 部署不友好。
|
|||
|
|
|
|||
|
|
两条路:
|
|||
|
|
- 保留“本地 Node 后端”(路径 A / B),让所有文件读写都在本地后端做
|
|||
|
|
- 或迁移到 Supabase Storage(推荐长期):mindmap 变成一个可版本化的对象文件(支持软删/回收站/延迟清理)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 观测与量化(否则很难证明“不卡了”)
|
|||
|
|
|
|||
|
|
建议先落地最小可用的观测:
|
|||
|
|
|
|||
|
|
1) 前端导航耗时
|
|||
|
|
- 在 `router.push` 前后打点(`performance.mark`),记录到 console 或上报
|
|||
|
|
|
|||
|
|
2) 关键 API 延迟
|
|||
|
|
- `/api/sidebar`、`/api/documents/content`、`/api/search/*`:记录开始/结束与 payload 大小
|
|||
|
|
|
|||
|
|
3) 体感指标
|
|||
|
|
- 首次可交互(TTI)
|
|||
|
|
- 文档打开到“编辑器可输入”的时间
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 下一步执行清单(建议按顺序)
|
|||
|
|
|
|||
|
|
1) 选择 Cloudflare 部署路径(A/B/C)
|
|||
|
|
2) P1:`FileTree` 虚拟化 + `assetsByDoc` O(n) 化 + `/api/sidebar` select 裁剪
|
|||
|
|
3) P2:公开页面缓存策略、上传直传、mindmap 存储迁移方案
|
|||
|
|
|