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

8.0 KiB
Raw Blame History

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.tswolai-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-frontendNext 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,哪些独立成后端服务”

路径 CCloudflare 运行 NextWorkers/Pages Functions+ 后端回源

适用场景:希望尽可能多逻辑在 Cloudflare 边缘,但愿意严格约束 Node 能力,重构较大。

现实结论:以当前代码结构(大量 fs/path/process.cwd())来看,除非先做较大改造,否则不建议直接走该路径。


2. 性能优化路线图(按优先级)

P0(已实现,立刻收益):文档内容按需加载,减小路由切换负担

已改动:

  • 新增 GET /api/documents/content?documentId=...:仅返回 documents.content
  • /documents/[id] 不再 select content,避免 RSC 携带大字段
  • 编辑器内容在客户端加载:DocumentContentinitialContent==null 时拉取内容并展示“页面内容加载中...”
  • BlockNoteEditornormalizedInitialContent 变化时重新初始化(只会从 null -> 实际内容 触发一次)

预期收益:

  • 切换页面时,RSC payload 更小、解析更快
  • 为 Cloudflare 反代/跨网访问(带宽较差)场景奠定基础

P1(强烈推荐,低风险高收益):侧边栏与文件树性能

  1. 文件树虚拟列表
  • FileTree 当前对 rows 直接 map 渲染,文档/附件数量上来后会明显卡顿
  • 已有 @tanstack/react-virtual 用例(PrivateTree),可复用同一技术栈把 FileTree 也做虚拟化
  1. assetsByDoc 构建从 O(n^2) 优化为 O(n)
  • 当前实现每次 push 前会 some() 去重(n 较大时会变慢)
  • 建议改为 Map<docId, Map<assetKey, asset>> 一次遍历构建
  1. /api/sidebar 数据裁剪与拆分
  • fetchSidebarDatasetmedia_assets 使用 select("*"),字段过多会拉大 payload
  • 建议改为只取侧边栏需要字段;并进一步拆分:
    • 文档树(documents
    • 垃圾桶(trashed docs/assets
    • 附件列表(只取当前展开节点/或按 docId 批量懒加载)

P2(中期):文档内容存储与传输优化(大文档体验)

  1. 内容分片/分页加载(可选)
  • documents.content 进行“块级分页”(例如按顶层 block 分块),在编辑器侧逐步加载
  1. 只拉取必要字段
  • 页面切换只拉 metatitle/updated_at/options/stats),内容按需加载(已完成)
  • backlinks / history 等面板可延迟加载或切换时懒加载
  1. 缓存与压缩策略(配合 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 或上报
  1. 关键 API 延迟
  • /api/sidebar/api/documents/content/api/search/*:记录开始/结束与 payload 大小
  1. 体感指标
  • 首次可交互(TTI
  • 文档打开到“编辑器可输入”的时间

5. 下一步执行清单(建议按顺序)

  1. 选择 Cloudflare 部署路径(A/B/C
  2. P1FileTree 虚拟化 + assetsByDoc O(n) 化 + /api/sidebar select 裁剪
  3. P2:公开页面缓存策略、上传直传、mindmap 存储迁移方案