Files
mnote/design/cloudflare-deploy-and-performance-optimization.md
T
2026-01-10 10:35:21 +08:00

171 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Cloudflare 部署与性能优化方案(全盘)
> 目标:前端可通过 Cloudflare 域名访问;后端(Supabase / LightRAG / ingest_service / Redis 等)通过 Cloudflare Tunnel 或等价方式对外暴露;同时解决当前“页面切换卡顿”的体感问题,并为后续 OCR(MinerU)与 RAG 自动入库留出扩展空间。
## 0. 现状结论(基于当前代码扫描)
### 0.1 当前代码对 CloudflareEdge/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 缓存静态资源缓解)
- 需要你保证本地服务稳定在线
### 路径 BCloudflare 部署“纯静态前端”(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,哪些独立成后端服务”
### 路径 CCloudflare 运行 NextWorkers/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) 只拉取必要字段
- 页面切换只拉 metatitle/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 存储迁移方案