Skip to content

Latest commit

 

History

History
130 lines (95 loc) · 7.17 KB

README.md

File metadata and controls

130 lines (95 loc) · 7.17 KB

tldraw sync server

This is a production-ready backend for tldraw sync.

  • Your client-side tldraw-based app can be served from anywhere you want.
  • This backend uses Cloudflare Workers, and will need to be deployed to your own Cloudflare account.
  • Each whiteboard is synced via WebSockets to a Cloudflare Durable Object.
  • Whiteboards and any uploaded images/videos are stored in a Cloudflare R2 bucket.
  • Although unreliated to tldraw sync, this server also includes a component to fetch link previews for URLs added to the canvas. This is a minimal setup of the same system that powers multiplayer collaboration for hundreds of thousands of rooms & users on www.tldraw.com. Because durable objects effectively create a mini server instance for every single active room, we've never needed to worry about scale. Cloudflare handles the tricky infrastructure work of ensuring there's only ever one instance of each room, and making sure that every user gets connected to that instance. We've found that with this approach, each room is able to handle about 30 simultaneous collaborators.

Overview

architecture

When a user opens a room, they connect via Workers to a durable object. Each durable object is like its own miniature server. There's only ever one for each room, and all the users of that room connect to it. When a user makes a change to the drawing, it's sent via a websocket connection to the durable object for that room. The durable object applies the change to its in-memory copy of the document, and broadcasts the change via websockets to all other connected clients. On a regular schedule, the durable object persists its contents to an R2 bucket. When the last client leaves the room, the durable object will shut down.

Static assets like images and videos are too big to be synced via websockets and a durable object. Instead, they're uploaded to workers which store them in the same R2 bucket as the rooms. When they're downloaded, they're cached on cloudflare's edge network to reduce costs and make serving them faster.

Development

To install dependencies, run yarn. To start a local development server, run yarn dev. This will start a vite dev server for the frontend of your application, and a wrangler dev server for your workers backend. The app should now be running at http://localhost:5137 (and the server at http://localhost:5172).

The backend worker is under worker, and is split across several files:

The frontend client is under client:

  • client/App.tsx: the main client <App /> component. This connects our sync backend to the <Tldraw /> component, wiring in assets and bookmark previews.

  • client/multiplayerAssetStore.tsx: how does the client upload and retrieve assets like images & videos from the worker?

  • client/getBookmarkPreview.tsx: how does the client fetch bookmark previews from the worker?

    Custom shapes

To add support for custom shapes, see the tldraw sync custom shapes docs.

Adding cloudflare to your own repo

If you already have an app using tldraw and want to use the system in this repo, you can copy and paste the relevant parts to your own app.

To point your existing client at the server defined in this repo, copy client/multiplayerAssetStore.tsx and client/getBookmarkPreview.tsx into your app. Then, adapt the code from client/App.tsx to your own app. When you call useSync, you'll need to pass it a URL. In development, that's http://localhost:5172/connect/some-room-id. We use an environment variable set in ./vite.config.ts to set the server URL.

To add the server to your own app, copy the contents of the worker folder and ./wrangler.toml into your app. Add the dependencies from package.json. If you're using TypeScript, you'll also need to adapt tsconfig.worker.json for your own project. You can run the worker using wrangler dev in the same folder as ./wrangler.toml.

Deployment

To deploy this example, you'll need to create a cloudflare account and create an R2 bucket to store your data. Update bucket_name = 'tldraw-content' in wrangler.toml with the name of your new bucket.

Run wrangler deploy to deploy your backend. This should give you a workers.dev URL, but you can also configure a custom domain.

Finally, deploy your client HTML & JavaScript. Create a production build with TLDRAW_WORKER_URL=https://your.workers.domain.com yarn build. Publish the resulting build (in dist/) on a host of your choosing - we use Vercel.

When you visit your published client, it should connect to your cloudflare workers domain and sync your document across devices.

License

This project is provided under the MIT license found here. The tldraw SDK is provided under the tldraw license.

Trademarks

Copyright (c) 2024-present tldraw Inc. The tldraw name and logo are trademarks of tldraw. Please see our trademark guidelines for info on acceptable usage.

Distributions

You can find tldraw on npm here.

Contribution

Please see our contributing guide. Found a bug? Please submit an issue.

Community

Have questions, comments or feedback? Join our discord or start a discussion. For the latest news and release notes, visit tldraw.dev.

Contact

Find us on Twitter/X at @tldraw.