首页
/ 如何用 Cloudflare Durable Objects 模板部署 tldraw 多人协作白板后端

如何用 Cloudflare Durable Objects 模板部署 tldraw 多人协作白板后端

2026-09-08 19:31:44作者:昌雅子Ethen

如果你的 tldraw 应用需要多人实时协作(共享画布、光标、在线状态),就必须自托管一个 tldraw sync 后端。tldraw 文档给出的两条自托管路径中,官方推荐的是直接部署 tldraw 仓库里的 Cloudflare 模板:它使用 Cloudflare Workers + Durable Objects 为每个房间提供独立的 WebSocket 服务,房间状态自动持久化到 Durable Object 内置的 SQLite 存储,图片和视频等大资源存到 Cloudflare R2 桶。部署完成后你会得到一个可用的多人协作白板后端,前端客户端通过 useSync 连接到它即可。

如何用 Cloudflare Durable Objects 模板部署 tldraw 多人协作白板后端 tldraw sync Cloudflare 模板架构:用户经 Workers 路由连接到各房间独占的 Durable Object,房间状态持久化在 SQLite,静态资源存放在 R2

后端由哪些部分组成

理解部署前的组件划分,方便验证时逐一对上:

  • /api/connect/:roomId:WebSocket 同步入口。请求被路由到该房间的 Durable Object,每个房间有且只有一个实例,所有连接该房间的用户都接到同一实例上(见 worker/worker.ts)。
  • TldrawDurableObject:同步 Durable Object,暴露 TLSocketRoom,负责在 WebSocket 客户端之间同步变更,并把房间状态写入内置 SQLite 存储,重启和休眠后数据仍在(见 worker/TldrawDurableObject.ts)。
  • /api/uploads/:uploadId:图片、视频的上传与下载,文件存入 R2 桶并走 Cloudflare 边缘缓存(见 worker/assetUploads.ts)。
  • /api/unfurl:书签形状的链接预览服务,提取 URL 元数据。
  • 客户端:通过 useSync hook 建连,模板中连接地址是 ${window.location.origin}/api/connect/${roomId}(见 client/pages/Room.tsx)。

准备工作

  1. 需要一个 Cloudflare 账号,并在其中创建一个 R2 桶,用于存放上传的图片、视频(模板 README 明确要求先建账号、再建 R2 桶)。

  2. 获取模板代码。两种方式任选其一:

    • 使用脚手架命令(Multiplayer starter kit 文档给出的方式,它拉取的就是本模板):

      npm create tldraw@latest -- --template multiplayer
      
    • 直接复制当前仓库中的 templates/sync-cloudflare 目录作为起点。

  3. 进入模板目录安装依赖:

    yarn
    

可选:先在本地跑通

本地开发用 yarn dev,它会启动一个 vite 开发服务器,通过 Cloudflare vite 插件同时运行前端和 Workers 后端,应用与服务器都应运行在 http://localhost:5137。先本地确认协作行为正常,再走部署流程,可以排除应用自身的问题。

修改 wrangler.toml 中的部署配置

wrangler.toml 是本次部署唯一必须修改的配置文件。模板当前内容与需要替换的部分:

name = "multiplayer-template"
main = "worker/worker.ts"
compatibility_date = "2025-05-08"
compatibility_flags = ["nodejs_compat"]

[[routes]]
pattern = "multiplayer.templates.tldraw.dev"
custom_domain = true

[assets]
not_found_handling = "single-page-application"
directory = "./dist/client"

[durable_objects]
bindings = [{ name = "TLDRAW_DURABLE_OBJECT", class_name = "TldrawDurableObject" }]

[[migrations]]
tag = "v1"
new_sqlite_classes = ["TldrawDurableObject"]

[[r2_buckets]]
binding = 'TLDRAW_BUCKET'
bucket_name = 'multiplayer-template'
preview_bucket_name = 'multiplayer-template-preview'

需要处理的三处:

  • bucket_name(必改):按模板 README 的说明,将其替换为你新建的 R2 桶名。注意 preview_bucket_name 是本地预览用的桶,模板当前指向 multiplayer-template-preview,本地跑 wrangler dev 预览时同样需要对应可用的桶。
  • [[routes]] 自定义域名:模板里绑定的 multiplayer.templates.tldraw.dev 是官方模板自己的域名。部署到你自己的 Cloudflare 账号后,默认会得到一个 workers.dev 地址;如果你想用自己的域名,把该节改成你的域名(README 指出也可以之后单独配置自定义域名)。
  • name:模板名为 multiplayer-template,建议改成你自己的应用名,避免与已有 Worker 冲突。

其余部分——Durable Object 绑定、new_sqlite_classes 迁移声明、[assets] 单页应用路由——保持模板原样即可。[assets] 一节说明 yarn build 产出的前端会一并作为静态资源部署,所以一次部署同时包含后端 Worker 和前端应用。

构建并部署到 Cloudflare

在模板目录执行:

yarn build
yarn wrangler deploy

yarn build 产出生产构建,yarn wrangler deploy 把后端 Worker 与前端应用一起部署到 Cloudflare,成功后你会得到一个 workers.dev 地址。部署目标地址就是你的多人协作后端入口。

验证部署结果

文档没有提供独立的健康检查命令,可用以下行为逐项确认后端工作正常:

  • 打开入口地址:访问 workers.dev 地址应能看到白板前端页面,进入某个房间后 URL 带上房间 ID。
  • 多人同步:在两个浏览器窗口(或无痕窗口)打开同一个房间链接。模板的协作表现是:房间内出现其他用户的在线状态(头像、姓名)和实时光标;一侧的修改会经 Durable Object 即时广播给另一侧。如果两人互不可见,检查是否同一房间 ID、两个客户端连的是不是同一后端。
  • 持久化:在房间中画入内容,刷新或重新打开同一房间链接,内容仍在。这是 Durable Object SQLite 存储在工作(房间状态自动持久化,无需手动保存逻辑)。
  • 资源上传:往画布里放入图片,确认其可正常回显,对应请求走 /api/uploads/ 并落到你的 R2 桶。
  • 书签预览:粘贴一个 URL 生成书签形状,应能拉取到链接预览元数据(/api/unfurl)。

一个文档明确给出的失败现象值得记住:若客户端与服务端的 tldraw 版本不匹配,tldraw 会显示 "please refresh the page" 提示。因此部署新客户端版本前,先保证新后端已上线。

已知限制

  • 版本一致性是硬要求:客户端与后端的 tldraw 版本必须一致。官方不保证后端永久向后兼容,偶尔会发布后端无法支持旧客户端的版本。文档建议后端与新客户端同步更新,并且新后端要先于新客户端上线。
  • 模板不含生产能力:同步文档明确说明,以下能力模板未提供,需要自行添加:身份认证与授权、上传的限流与大小限制、按时间留存文档快照、房间列表与搜索。
  • 单房间规模:模板 README 提到 tldraw.com 使用同一套系统,每个房间大约能支撑 50 人同时协作。这个数字来自 README 的表述,作为规模参考而非承诺值。
  • 模板 Worker 开启了 CORS(因为示例中 Worker 与客户端可能分开部署),源码注释提醒:接入自己的应用时应把 CORS 限制到自己的域名。

替代路径与延伸阅读

  • 如果不想用 Durable Objects,@tldraw/sync-core 也支持接入任意支持 WebSocket 的 JavaScript 后端,仓库中有 simple-server-example 作为参考实现(配合 InMemorySyncStorageSQLiteSyncStorage)。
  • 已有自研应用想复用这套后端时,模板 README 的 "Adding cloudflare to your own repo" 一节给出做法:把 worker/ 目录和 wrangler.toml 拷入你的应用,加上 package.json 中的相关依赖,用 wrangler dev 本地运行;客户端侧拷贝 client/multiplayerAssetStore.tsxclient/getBookmarkPreview.tsx,并把其中 /api/ 地址改指向你的新服务器。
  • 自定义形状需要客户端与服务端两侧同时注册 schema,完整说明见 tldraw sync 文档Multiplayer starter kit 文档
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391