8.0 KiB
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(强烈推荐,低风险高收益):侧边栏与文件树性能
- 文件树虚拟列表
FileTree当前对rows直接map渲染,文档/附件数量上来后会明显卡顿- 已有
@tanstack/react-virtual用例(PrivateTree),可复用同一技术栈把FileTree也做虚拟化
assetsByDoc构建从 O(n^2) 优化为 O(n)
- 当前实现每次 push 前会
some()去重(n 较大时会变慢) - 建议改为
Map<docId, Map<assetKey, asset>>一次遍历构建
/api/sidebar数据裁剪与拆分
fetchSidebarDataset对media_assets使用select("*"),字段过多会拉大 payload- 建议改为只取侧边栏需要字段;并进一步拆分:
- 文档树(documents)
- 垃圾桶(trashed docs/assets)
- 附件列表(只取当前展开节点/或按 docId 批量懒加载)
P2(中期):文档内容存储与传输优化(大文档体验)
- 内容分片/分页加载(可选)
- 对
documents.content进行“块级分页”(例如按顶层 block 分块),在编辑器侧逐步加载
- 只拉取必要字段
- 页面切换只拉 meta(title/updated_at/options/stats),内容按需加载(已完成)
- backlinks / history 等面板可延迟加载或切换时懒加载
- 缓存与压缩策略(配合 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. 观测与量化(否则很难证明“不卡了”)
建议先落地最小可用的观测:
- 前端导航耗时
- 在
router.push前后打点(performance.mark),记录到 console 或上报
- 关键 API 延迟
/api/sidebar、/api/documents/content、/api/search/*:记录开始/结束与 payload 大小
- 体感指标
- 首次可交互(TTI)
- 文档打开到“编辑器可输入”的时间
5. 下一步执行清单(建议按顺序)
- 选择 Cloudflare 部署路径(A/B/C)
- P1:
FileTree虚拟化 +assetsByDocO(n) 化 +/api/sidebarselect 裁剪 - P2:公开页面缓存策略、上传直传、mindmap 存储迁移方案