Wordgard — новый редактор текста от создателя ProseMirror
Технический обзор · Июль 2026

Wordgard 0.1:
Новый редактор текста от создателя ProseMirror

Марейн Хавербеке выпускает свой шестой редактор — полная переработка архитектуры с учётом девяти лет опыта. Дельта-формат изменений, компонуемые схемы и собственное управление выделением.

Олег Максимов 10 июля 2026 12 мин чтения

Введение

2 июля 2026 года Марейн Хавербеке — создатель ProseMirror и CodeMirror, двух самых влиятельных библиотек редактирования текста в экосистеме JavaScript — анонсировал новый проект под названием Wordgard. По его собственному подсчёту, это шестой нетривиальный редактор, который он построил.

Wordgard — это не ProseMirror 2.0. Это полная переработка с нуля, вобравшая всё, что Хавербеке узнал за девять лет поддержки ProseMirror, плюс архитектурные находки из переработки CodeMirror 6. Программный интерфейс построен заново, без оглядки на совместимость.

Эта статья — технический разбор архитектуры Wordgard: дельта-формат изменений, заменивший шаги ProseMirror, компонуемая система схем, отказ от регулярных выражений для ограничения контента, система расширений на фацетах из CodeMirror 6 и новый подход к управлению выделением независимо от браузера. Если вы работаете с редактированием форматированного текста или следите за дизайном JavaScript-библиотек, этот релиз стоит понимания.

Что не так с ProseMirror?

ProseMirror никуда не уходит — Хавербеке продолжит его поддерживать. Но девять лет реального использования выявили архитектурные решения, которые он теперь считает ошибками. Вместо того чтобы пытаться исправить их обратно-совместимым способом (что дало бы, по его словам, «скомпрометированный win32-подобный бардак»), он выбрал чистый разрыв.

Ключевые проблемы, которые решает Wordgard:

Дельта-формат изменений

ProseMirror представляет изменения как последовательность шагов (steps), где каждый шаг работает с документом, полученным после предыдущего. Шаги атомарны, каждый делает одно чёткое действие, но с ними «серьёзно неудобно работать», как выражается Хавербеке. Чтобы понять, какой диапазон документа был заменён, нужно пройти по последовательности шагов в обоих направлениях, маппируя позиции вперёд и назад.

Wordgard заменяет это дельта-форматом, заимствованным из ShareJS и доработанным в CodeMirror 6. Изменение — это плоская последовательность секций, каждая из которых либо:

Для плоского документа длиной 10 вставка буквы «L» в позиции 4 выглядит так:

[keep 4] [replace 0 with "L"] [keep 6]

Удаление первых двух символов:

[replace 2 with ""] [keep 8]

Секция update — новая концепция, отсутствующая в текстовом дельта-формате CodeMirror. Она сохраняет структуру секции, но добавляет или удаляет разметку (выделение жирным, стиль ссылки, alt-текст изображения). Сделать слово с 3 по 6 позиции жирным:

[keep 3] [update 3 +bold] [keep 4]

Поскольку Wordgard использует систему индексации на основе подсчёта токенов (как и ProseMirror), дельта-формат адресует документ как плоскую последовательность токенов — открывающие/закрывающие токены узлов и листовые токены — и вставляет в неё новые последовательности. Это работает для форматированного контента благодаря фиксирующим механизмам, обеспечивающим структурную валидность.

Такие дельты легко комбинировать: одна транзакция всегда имеет одно связанное изменение, которое легко инспектировать и анализировать. Они также поддерживают ограниченную форму операционной трансформации (ОТ), позволяя объединять изменения, описанные относительно одного и того же исходного документа. Это даёт:

Валидность на уровне токенов и фиксация

Документ на самом деле не является плоской последовательностью токенов — токены имеют смысл только в组合и, образующей хорошо сформированное дерево. Если удалить закрывающий токен узла, документ становится несбалансированным, и изменение не может быть применено напрямую. Код создания изменений в Wordgard включает проверки и коррекции для обеспечения валидности всех изменений.

Для операционной трансформации задача сложнее: трансформация изменения A для применения после B должна давать тот же результат, что и трансформация B для применения после A (конвергенция). Wordgard решает это с помощью механизма фиксирующего изменения (fix-up). При трансформации изменений система выводит коррекцию, которая применяется к обоим результатам трансформации одинаково, гарантируя сходимость обоих путей к одному валидному документу.

Композиция схем

В ProseMirror схемы документов задают отношения между узлами напрямую — типы узлов и разметки существуют только внутри конкретной схемы. Это затрудняет композицию схем и обмен функциональностью между ними.

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

Композиция схемы — просто сбор нужных элементов:

import { schema } from "wordgard"
import { heading, paragraph } from "wordgard/block"
import { em, strong, link } from "wordgard/mark"

const mySchema = schema([heading, paragraph], [em, strong, link])

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

Такой дизайн делает переиспользуемые расширения значительно более жизнеспособными. В ProseMirror схема была настолько общей, что код либо был привязан к конкретной схеме, либо не мог знать, что означают элементы. В Wordgard встроенные узлы полезны «из коробки», и расширения могут работать с ними напрямую.

Ещё одно улучшение: в ProseMirror атрибуты узлов (например, выравнивание текста или alt-текст) определяются непосредственно на типе узла. Добавление выравнивания ко всем текстовым блокам требовало модификации каждого узла. Wordgard обобщает разметку (marks) для таких целей, сохраняя типы узлов чистыми и позволяя модульно добавлять атрибуты стилизации.

Ограничения контента: от регулярных выражений к коррекциям

Фирменная функция ProseMirror — возможность задавать разрешённое содержимое для родительского узла с помощью регулярного выражения — убрана в Wordgard. Описание контента может ограничивать только типы разрешённых потомков, но не их порядок.

Причина двоякая. Во-первых, ограничения на основе регулярных выражений делают универсальный код манипуляции документом чрезвычайно сложным. Код, не написанный для конкретной схемы, не может ничего предполагать о допустимых трансформациях, требуя проверки каждой операции против выражения контента. Даже сам Хавербеке признаётся, что допускал ошибки в таком коде ProseMirror.

Во-вторых, жёсткая фиксация формы документа часто вредит пользовательскому опыту. Документы редактируются через серию маленьких инкрементальных действий. Если редактор блокирует промежуточные состояния с нестандартной формой документа, пользователи испытывают frustration.

Wordgard заменяет это абстракцией под названием коррекция (correction) — программной функцией, исправляющей нежелательные формы документа. Коррекции лучше потому что:

import { correction } from "wordgard"

const tableCorrection = correction((doc) => {
  // Обеспечить одинаковое количество ячеек во всех строках таблицы
  // Выражения контента ProseMirror не могли этого выразить
})

Система расширений: фацеты из CodeMirror 6

Система расширений ProseMirror позволяет плагинам влиять на систему, но каждый плагин делает несколько вещей одновременно. Приоритет плагинов глобален — можно менять их порядок, но один плагин может нуждаться в высоком приоритете для одной своей функции и низком для другой.

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

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

import { extensionGroup, keyBinding, stateEffect } from "wordgard"

const boldFeature = extensionGroup(
  keyBinding({ key: "Mod-b", run: toggleBold }),
  stateEffect("bold", (state) => ({ ...state, bold: !state.bold })),
  // Ещё расширения, которые автоматически компонуются
)

Примитивы, на которых строятся расширения, спроектированы для чистой композиции. Вы можете добавлять наборы расширений в конфигурацию и ожидать, что они будут работать вместе без конфликтов. Это значительное улучшение качества жизни по сравнению с системой плагинов ProseMirror.

Уменьшение зависимости от браузера

Один из главных источников проблем ProseMirror — опора на нативную реализацию выделения браузера. Идея была разумной — движение курсора в двунаправленном тексте со стилизованным контентом сложно. Но на практике браузеры делают эту работу «недостаточно хорошо».

Wordgard применяет другой подход: он реализует почти всё управление выделением самостоятельно. Для этого потребовалось:

Единственное исключение — сенсорное выделение, которое остаётся нативным, потому что его переопределение ломает системное контекстное меню — критичное для телефонов и планшетов. К счастью, сенсорное выделение имеет меньше странных проблем, чем клавиатурное.

Поддержка браузерами событий редактирования — особенно beforeinput — значительно улучшилась за последние девять лет. Wordgard обрабатывает события beforeinput для всего, кроме композиционного ввода текста, избегая целого класса обходных путей, необходимых ProseMirror для мониторинга и разбора изменений DOM.

Статус, лицензия и модель сообщества

Wordgard 0.1 доступен в npm как wordgard. Основной интерфейс поддерживает почти всё, что запланировал Хавербеке, а набор расширений подтверждает практичность дизайна. Документация, включая полное справочное руководство, доступна на wordgard.net.

Библиотека выпущена под лицензией MIT. Хавербеке серьёзно рассматривал более строгую лицензию, но решил, что его модель работы — это модель изобилия: предоставлять достаточно ценности, чтобы даже малая часть возвращалась к нему как доход. Он прямо осуждает использование своего кода для обучения ИИ, но признаёт, что мало что может с этим сделать, сохраняя систему доступной.

Важное отклонение от стандартной практики open-source: Wordgard не принимает пулл-реквесты. Хавербеке считает, что рецензирование и согласование крупных изменений требует больше работы, чем их самостоятельная реализация, а с ростом объёмов AI-генерируемого кода он предпочёл развивать проект самостоятельно.

План — оставаться на версиях 0.x как минимум год для сбора обратной связи, исправления ошибок и уточнения публичного API. Как и с любым релизом 0.1, к продакшену стоит подходить с осторожностью — но для экспериментов и раннего внедрения Wordgard продвинулся дальше, чем предыдущие проекты Хавербеке на момент анонса.

Часто задаваемые вопросы

Что такое Wordgard?
Wordgard — это новая библиотека для редактирования форматированного текста от Марейна Хавербеке, создателя ProseMirror и CodeMirror. Это полная переработка архитектуры, исправляющая архитектурные ошибки, накопленные за девять лет поддержки ProseMirror. Wordgard предлагает дельта-формат изменений, компонуемые схемы с независимыми типами узлов, расширения на фацетах и собственную обработку выделения без зависимости от браузера.
Чем Wordgard отличается от ProseMirror?
Wordgard заменяет представление изменений ProseMirror через «шаги» на дельта-формат, заимствованный из CodeMirror 6 и ShareJS. Он убирает регулярные выражения для ограничения контента в пользу программных «коррекций». Типы узлов и разметки независимы от схем, что упрощает композицию. Система расширений использует фацеты CodeMirror 6 для точного контроля приоритетов. Wordgard также обрабатывает клавиатурное и указательное выделение самостоятельно, вместо того чтобы полагаться на DOM-выделение браузера.
Поддерживает ли Wordgard совместное редактирование?
Да. Дельта-формат изменений поддерживает ограниченную форму операционной трансформации, позволяя объединять изменения, описанные относительно одного и того же исходного документа. Это даёт Wordgard нативную поддержку совместного редактирования и историю отмены, способную выборочно отменять отдельные изменения. Алгоритм трансформации включает механизм фиксации, обеспечивающий валидность документа после слияния конкурентных правок.
Можно ли использовать Wordgard в продакшене?
Wordgard находится на версии 0.1 по состоянию на июль 2026 года. Основной интерфейс поддерживает почти все запланированные возможности, и написано несколько расширений для проверки дизайна. Справочное руководство завершено и пригодно к использованию. Однако Хавербеке планирует оставаться на версиях 0.x как минимум год для сбора обратной связи, исправления ошибок и уточнения публичного API. Библиотека пригодна для экспериментов, но для продакшена требуется осторожная оценка.
Под какой лицензией выпущен Wordgard?
Wordgard выпущен под лицензией MIT, как и ProseMirror с CodeMirror. Хавербеке серьёзно рассматривал более строгую лицензию, но выбрал MIT для максимального распространения. Важное отклонение от стандартной практики open-source: Wordgard не принимает пулл-реквесты — Хавербеке предпочитает реализовывать изменения самостоятельно для сохранения целостности дизайна.
Что такое дельта-формат в Wordgard?
Дельта-формат Wordgard представляет изменения как последовательность секций: каждая секция либо сохраняет часть старого документа, либо заменяет её новым содержимым, либо обновляет разметку существующего содержимого. Например, вставка 'L' в позиции 4 в документе из 10 символов выглядит как [keep 4][replace 0 with 'L'][keep 6]. В отличие от шагов ProseMirror (которые цепляются последовательно и требуют маппинга позиций), дельты Wordgard можно комбинировать и трансформировать относительно одного базового документа.
Можно ли мигрировать с ProseMirror на Wordgard?
Wordgard — это полная переработка с несовместимым публичным API. Пути миграции с ProseMirror не существует — вам придётся создавать интеграцию редактора с нуля. Многие концепции переносятся (схемы, узлы, разметка), но программный интерфейс полностью новый. Хавербеке намеренно создал новый проект вместо ProseMirror 2.0, чтобы избежать путаницы в том, о какой версии идёт речь.

Заключение

Wordgard — значительная веха в дизайне JavaScript-библиотек для редактирования текста. Хавербеке взял всё, чему научился на двух самых широко используемых редакторских библиотеках в экосистеме, и переплавил в более чистую, более компонуемую архитектуру.

Дельта-формат изменений, независимые элементы схем, система коррекций и фацеты из CodeMirror 6 — каждое из этих решений адресует конкретную болевую точку из девятилетней истории ProseMirror. Вместе они представляют зрелую дизайнерскую философию, ставящую эргономику разработчика и компонуемость выше теоретической чистоты.

Разработчикам, создающим приложения, которым нужно редактирование форматированного текста — системы управления контентом, платформы для совместной работы, базы знаний или структурированные редакторы документов — стоит присмотреться к Wordgard. Он ещё молод, но фундамент прочен, а дизайнерские решения хорошо документированы и обоснованы.

Если вы рассматриваете проект по разработке сайта или веб-приложения, связанный с редактированием текста или любой другой сложной фронтенд-задачей, свяжитесь со мной — я full-stack разработчик с опытом во всей экосистеме JavaScript и помогу выбрать правильные инструменты для ваших задач.

Связаться

Работаете над проектом с редактированием текста?

Расскажите о проекте — я помогу выбрать правильный подход и архитектуру. Бесплатная первичная консультация.