Coder Social home page Coder Social logo

quill-demo's Introduction

Intro

This repository demonstrates using yjs and y-py to synchronize a quilljs canvas between clients. The js-frontend directory is a nearly unchanged copy of the yjs-demos Quill example. Instead of pointing to a public websocket host, it points to a local backend server written in Python and the FastAPI framework. The backend keeps its own YDoc model using y-py. Finally, the most unique part of this demonstration is the python-frontend. That replaces the Quill - yjs binding and y-websocket provider with y-py / Python running in a webworker with pyodide.

Setup

Bootstrap your system to install npm and python, I recommend using nvm and pyenv. The python-frontend directory specifies using Python 3.10.2 so that IDE support when writing static/worker.py will match the version of Python when it's compiled to webassembly and run within Pyodide v0.21.3 (specified in static/worker.js).

Run

Start all three servers:

  • cd backend && poetry install && poetry run uvicorn app:app (default port is 8000)
  • cd js-frontend && npm start (default port is 8081)
  • cd python-frontend && poetry install && poetry run uvicorn app:app --port 8082

If you need to switch ports around because you have other things running on your machine, just make sure to update the websocket urls in js-frontend/quill.js and python-frontend/static/worker.py to point to the backend server.

y-py in Pyodide

y-py are Python bindings to yrs, the Rust implementation of the y-crdt algorithm. That means it is not a pure Python package, so wheels need to be built for each target machine you want to install it on. In this case, we want to install it in Pyodide 0.21.3, so the target machine is cp310 (Pyodide 0.21.3 runs Python 3.10.2) and emscripten 3-1-14 wasm32.

Unfortunately, PyPI does not host wasm wheels. See y-py PR's 91, 99, and 103 for ongoing attempts to build a wasm wheel as part of a y-py release and attach the binary as an asset in github. For the sake of this demo, a copy of the wheel is just included in the repo and served out as a static file. See python-frontend/static/worker.js for implementation of writing and installing the wheel from emscripten disk (emfs:<path>).

Webworker flow

When you're reading the python-frontend code, it might help to think about the workflow as follows:

  1. Browser asks for index.html, python-frontend FastAPI server hands over that static file
  2. index.html spawns a webworker, and the script to execute in that thread is the static file worker.js
  3. worker.js pulls in pyodide and then runs Python code (in webassembly) to:
  • Load micropip
  • Download y-py wasm wheel static file, write it to emscripten file system, and pip install from disk
  • Install ypy-websocket from pypi.org
  • Download worker.py static file, write it to emscripten file system
  • import worker
  1. On import, worker.py:
  • Instantiates QuillBinding, which will send a message over webworker for index.html to enable quill canvas
  • Instantiate WebsocketProvider, which establishes the websocket connection and begins sync steps
  • Set an onmessage handler for messages coming from main js thread to the webworker thread that worker.py is in

Issues

  • Obviously missing plenty of features in this demo, such as awareness protocol and websocket disconnect/reconnect in python-frontend
  • Setting attributes on existing text (e.g. select text, toggle italics on/off) syncs when done in the js-served window but doesn't when initiated from python-frontend
  • Putting in data (e.g. pasting screenshot) fails in python-frontend with error TypeError: argument 'chunk': 'dict' object cannot be converted to 'PyString'
  • yrs / y-py doesn't have an origin argument in the transaction
  • It would be nice if synchronization message helpers were implented in yrs rather than in ypy-websocket utils
  • If you have more than one tab open from js-frontend and restart backend, the two frontends will have a shared YDoc state that's out of sync with backend, so any new updates aren't captured server-side nor broadcast over websocket (they still sync between tabs thanks to y-websocket js). Closing the second tab then refreshing the first gets you synced again

quill-demo's People

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.