Сократите техническую сложность, сосредоточившись на пользовательском опыте. Избегайте ненужного общего состояния при совместном редактировании.

Фреймворк Yjs добавляет передовые возможности совместного редактирования в ванильные текстовые редакторы Prosemirror. Он превращает процесс сохранить и закрыть в режим, в котором многие пользователи пишут все одновременно.

Ключевым элементом совместного редактирования является отображение курсоров других пользователей, чтобы можно было понять, почему появился новый фрагмент текста. И чтобы различать, кто именно внес изменения, каждый курсор должен иметь уникальный цвет.

Библиотека интеграции Prosemirror/Yjs, y-prosemirror, поставляется с модулем курсора, который сохраняет цвет каждого пользователя в общем состоянии (протокол осведомленности). Каждый подключенный пользователь берет реплицированные цвета и отображает курсоры.

При этом у нас были все компоненты для создания первоклассного совместного редактирования. И тут наступила реальность…

Выбор цвета оказался намного сложнее, чем мы предполагали. Например, что произойдет, если два пользователя присоединятся одновременно и выберут один и тот же цвет? Они оба выбирают новый цвет — или только один из них? Как они договариваются, кто из них выберет новый цвет? Сколько длится «присоединиться одновременно»? Повторное присоединение считается присоединением или пользователь должен сохранить цвет в этой ситуации? Что делать, если два пользователя с конфликтующими цветами воссоединятся? Здесь мы ответили на все сложные вопросы из учебников по распределенным системам.

Создание для пользователей — не наука

У нас был момент озарения, когда мы изменили нашу точку зрения с «распределенных систем» на «пользовательский опыт». Все стало яснее, когда мы спросили себя: «Если Алиса, Боб и Чарли работают в одном и том же документе, насколько важно, чтобы курсор Чарли был красным для Алисы и Боба?» Мы быстро поняли, что на пользовательский опыт не влияет, если Алиса видит Чарли как «красный курсор», а Боб видит его как «синий курсор».

Это означало, что на самом деле не было необходимости синхронизировать цвета между пользователями, что означало отсутствие сложных проблем с распределенной системой. Ага!

Итак, вот что у нас получилось: Каждый пользователь ведет упорядоченный список пользователей, которых он когда-либо видел подключающимися. На основе этого списка цвет выбирается из списка доступных цветов. Не удаляя отключенных пользователей, мы гарантируем, что каждый пользователь всегда будет использовать один и тот же цвет. Вот набросок:

const handleAwarenessChange = ({ added }) => {
   added.forEach(clientId => {
    if (!allClientIds.includes(clientId)) {
     allClientIds.push(clientId);
    }
   });
   ...
});
observable.on('change', handleAwarenessChange);
function computeColor(clientId: number, allClientIds: number[]) {
  const nrConnected = allClientIds.indexOf(clientId);
  return COLORS[nrConnected % COLORS.length];
}

Удачного кодирования!

➡️ Вы хотите больше работать с Prosemirror & Yjs? NEXT ищет Prosemirror разработчика (удаленно, на полную ставку). Подайте заявку сейчас!