История создания Editor.js — модульного визуального редактора от команды студентов CodeX Статьи редакции

На его основе работает редактор vc.ru, TJ и DTF.

Три с половиной года разработки, 24 репозитория, 500 закрытых пулл-реквестов и бессчётное число коммитов — большой opensource-проект готов к выходу из беты.

Если быть точным, это вторая версия проекта, в которой мы решили изменить название редактора с CodeX Editor на Editor.js, попутно переписав его с нуля. В статье я расскажу о пути, который прошла команда от первых набросков до релиза на Product Hunt.

CodeX

Осенью 2015 года состоялась первая встреча клуба веб-разработки: студенты и молодые разработчики сформировали команду энтузиастов для изучения новых технологий, экспериментов и исследований. На второй встрече, вместе с запуском сайта, нам понадобился визуальный редактор, в котором мы могли бы писать статьи о своих экспериментах. В тот же вечер в репозиторий CodeX Editor был отправлен первый коммит.

Сегодня CodeX — это по-прежнему небольшая команда, но с большой (97 репозиториев!) инфраструктурой собственных opensource-библиотек и микросервисов, интегрированных друг с другом. А CodeX Editor 2.0 или Editor.js — один из наших крупнейших и основных проектов.

О редакторе

Основная концепция — блочная структура и чистые данные в виде JSON на выходе. В отличие от большинства редакторов, где пользователь работает с текстом внутри одной редактируемой обертки, в Editor.js каждый структурный элемент статьи — блок — это отдельный редактируемый элемент.

Блоки могут быть какие угодно: абзацы, заголовки, цитаты, списки, изображения, твиты, опросы и так далее.

После сохранения редактор возвращает данные о каждом блоке.

{ "time" : 1550476186479, "blocks" : [ { "type" : "paragraph", "data" : { "text" : "The example of text that was written in Editor.js" } }, { "type" : "header", "data" : { "text" : "With the header of course", "level" : 2 } }, { "type" : "paragraph", "data" : { "text" : "So what do we have?" } } ], "version" : "2.8.1" }

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

Именно простота API и стала самой сложной и самой удачной идеей.

Первая версия

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

В качестве образцов блоков мы написали первые плагины: «Параграф», «Заголовок», «Картинка», «Список» и еще некоторые. Старались придумать примеры разных сценариев: от простого набора и оформления текста до плагинов, взаимодействующих с серверной частью. Это позволило развивать API, который даёт возможность создать абсолютно любой плагин.

Например, плагин Twitter по вставленной в текст ссылке должен был формировать виджет твита. Для этого на страницу надо предварительно подключить Twitter SDK — так в API появился метод 'prepare'. При инициализации редактор собирает prepare всех плагинов, запускает их и дожидается завершения перед отрисовкой интерфейса.

Осенью 2016 года мы внедрили первую версию на наш сайт, а также в контент-сервис CodeX Media. Примерно в это же время в «Комитете» началась разработка новой модульной платформы для изданий Osnova — и в качестве редактора выбрали CodeX Editor.

Форк Paragraph

В «Комитете» на всех платформах развиваются мощные UGC-сообщества. Каждый пользователь может написать и опубликовать материал, а одна из задач платформы — снизить шансы на то, что вёрстка будет некачественная и некрасивая.

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

Помимо этого, JSON-структура позволяет легко извлекать нужные данные из материала. Например, можно получить первый блок с картинкой и использовать его как обложку для соцсетей в meta-информации. Или получить первый текстовый блок и выводить его в ленте.

Опять же за счет блочной структуры, материалы можно верстать отдельно для веба и мобильных приложений, для Instant Articles, Google AMP и даже озвучивать голосом.

Уже за первые месяцы работы редактора на DTF удалось поправить большое количество мелких багов и узких необработанных кейсов.

Чтобы разграничить зоны ответственности, мы создали приватный форк CodeX Editor, получивший название Paragraph. Он решает задачи платформы, развиваясь, совершенствуя дизайн и повышая стабильность. Основной упор сделали на разработку новых плагинов и совершенствование имеющихся.

На сегодняшний день разработка Editor.js и Paragraph ведется параллельно.

Вторая версия

Лето 2017 года. Мы в CodeX решили устроить ивент: снять на неделю коттедж в лесу на берегу озера и днями и ночами работать плечом к плечу, осваивая новую область технологий: AR.

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

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

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

  • Появилась возможность инициировать несколько редакторов на странице параллельно.
  • Полностью обновлен и проработан API: убраны избыточные методы, названия и структура стали более логичными, появились новые возможности. Обратной совместимостью решили пожертвовать — слишком уж хорош получался новый интерфейс, а клиентов, кроме нас самих, к тому времени практически не было, ведь проект нигде не анонсировался.
  • Появился API для разработки не только плагинов для блоков, но и инструментов форматирования — выделения фрагментов текстов маркером, вставки инлайнового кода, ссылок и так далее.
  • Настройки блоков тоже стали плагинами: например, можно создать настройку «Спойлер», которая появится у всех блоков и будет сворачивать их содержимое.
  • Проект был полностью переписан на TypeScript. Это повысило надежность и улучшило структуру модулей.
  • Появилась подробная документация API и циклы гайдов по написанию плагинов.

На реализацию новых возможностей и переписывание кода ушел ни много ни мало год. И летом 2018 года мы анонсировали открытое бета-тестирование проекта.

Бета-тестирование

Запуск беты мы анонсировали в нашем небольшом паблике и Telegram-канале. Несмотря на малое число подписчиков, появились заинтересованные в продукте люди, и со временем их становилось все больше.

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

Это принесло свои результаты — в ходе тестирования многие моменты были улучшены, а на многие вещи удалось взглянуть со стороны. Где-то понадобилось улучшить документацию, а где-то изменить API.

Доработок и новых идей оказалось столько, что запланированный месяц тестирования вылился в пять. Где-то в середине мы поняли, что название CodeX Editor не самое удачное — большинство людей называли редактор просто CodeX. Домен editorjs.io оказался свободен.

Затянувшийся ремонт подошел к концу.

Релиз

Выпуск продукта оказался непростой задачей: требовалось не только протестировать код и сверстать лендинг, но и провести большой объем мероприятий по подготовке к запуску полноценного комьюнити.

Мы написали десятки гайдов и статей для разработчиков плагинов, сняли множество поясняющих GIF-анимаций, тщательно проработали документацию API, создали отдельную организацию на GitHub, в которой будут публиковаться лучшие плагины и дополнения.

За все время работы над проектом главным мотиватором каждого члена команды был предстоящий момент релиза. Под ним мы подразумевали публикацию проекта во всемирном хит-параде продуктов Product Hunt.

И сегодня этот день настал. Представляем вашему вниманию Editor.js 2.0 — новый редактор и новая большая opensource-история.

0
26 комментариев
Написать комментарий...
Robert Marley

Отличный редактор !
А он открытый ? его в своих проектах юзать можно будет ?
(принцип тот же остался - на сервер типа массив параграфов уходить будет ?)
Спасибо !

Ответить
Развернуть ветку
Егор Бережной

Привет!

Исходный код открыт и выложен на гитхабе :)
Вот тут можно найти ядро — https://github.com/codex-team/editor.js, а здесь наши плагины — https://github.com/editor-js

Ядро распространяем под лицензией Apache-2.0 (можно делать все, что угодно, упоминая оригинальную лицензию), плагины под MIT.

Формат данных и другие подробности есть в документации — https://editorjs.io

Ответить
Развернуть ветку
Альберт Штерн

Привет!
А как это работает на мобильных экранах?
Очень хочется встроить, но под адаптив возможно ли.

Ответить
Развернуть ветку
Пётр Савченко
Автор

Примерно так. Стили можно настроить любые.

На телефонах работает, но пока не очень удобен для написания больших текстов. Релиз поможет собрать и структурировать проблемы.

Ответить
Развернуть ветку
Франциск КороваЗаДрова

А эти сайты тоже на вашем?

https://spark.ru
https://www.klerk.ru

Ответить
Развернуть ветку
Pixel Lens

Обожаю редакторы как на комитете, телеграфе, телетайпе и вордпрессе.ком (именно ком).

Крутая штука!

Ответить
Развернуть ветку
Ярослав Белов

Восхищаюсь вашей работой. Спасибо большое! Как пользователь ранее использовал другие предложения рынка, но теперь я точно знаю куда смотреть) На ханте апвот оставил.
Подскажите, пожалуйста, на вашем сайте https://editorjs.io/ вижу примечание связанное с видео, но в редакторе тестирую возможности и его не нахожу. Как добавить видео? А второй вопрос, возможно ли добавлять иной код, например плейлист с Я.музыка?

Ответить
Развернуть ветку
Пётр Савченко
Автор

Все зависит от плагинов, которые вы будете использовать. Для любой задачи можно написать свой плагин.

Мы написали несколько для примера:
https://github.com/editor-js

У нас есть плагин Image, который поддерживает загрузку гифок и mp4, но требуется серверная имплементация

Есть плагин Embed, который позволяет вставлять YouTube, Vimeo и тд по ссылкам. Кстати, Яндекс.Музыку тоже поддерживает.

Ответить
Развернуть ветку
Ярослав Белов

Спасибо, Пётр, за ответ. Буду изучать. Желаю вам новых побед!

Ответить
Развернуть ветку
Andrey Ramin

Очень здорово! Этот мир нуждается в хороших WYSIWYG-редакторах :)
В сравнении с draft.js вы не стали пытаться работать с внутренним состоянием блока и просто оставили там html. Надо сказать, решение изящное (я в свое время не сработался с draft.js/slate.js — слишком много приходится кода вокруг писать, и результат не стабилен), но вдруг захочется большего? Например, есть ли возможность (или появится), сохранить в JSON блока дополнительные ключи с какими-либо данными и соответствует ли это философии проекта?
А можете вкратце написать, как вы работаете с состоянием (обновлением) редактора (понятно, что можно подсмотреть в коде), но хотелось бы ваш взгляд, почему сделали так, а не иначе. И проверяли ли на больших текстах (от 40 тыс. знаков)?
Наконец, вопрос про хранение в JSON. Если вы настраиваете поиск по тексту, насколько все усложняется? (логично хранить это в jsonb постгреса — подозреваю, что у вас так и есть)

Ответить
Развернуть ветку
Пётр Савченко
Автор

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

Про дополнительные поля в JSON — прямо в точку. Уже проектируем такой уровень API. Нужен нам для плагина комментариев.

Про состояние, если совсем кратко, используем Proxy. То есть у нас по сути написан реактивный диспетчер блоков — добавили или изменили блок в массиве, он изменился в DOM.

Про хранение JSON планируем написать отдельную заметку в документации. У нас по разному везде. Тут, например jsonb. Elasticsearch легко интегрируется.

Ответить
Развернуть ветку
Макс Туторев

вроде интересная штука, надо юзануть

Ответить
Развернуть ветку
Serge Bezborodov

спасибо большое за работу!
когда то юзали sir trevor https://madebymany.github.io/sir-trevor-js/ но его забросили

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Вадим Куницын

давно слежу за вашим проектом. Надеюсь выпустят интеграции с популярными CMS.

Ответить
Развернуть ветку
Artem Ivanov

хорошая альтернатива MediumEditor

Ответить
Развернуть ветку
Timur Sarsembayev

Замечательно!

Ответить
Развернуть ветку
Jack Stepanyan

есть план интегрирования в react/angular ?

Ответить
Развернуть ветку
Alexander Menshikov

Сейчас как раз обсуждаются дальнейшие планы и интеграции в том числе.
Кстати, сообщество вокруг редактора уже пилит свои обёртки. Например, враппер для Vue.js – https://github.com/ChangJoo-Park/vue-editor-js

Ответить
Развернуть ветку
Ilya G

Редактор прекрасен и спасибо за вашу работу.
Если позволите, небольшой вопрос: возможно, при разработке редактора вы держали в голове и решение хранения данных из json на бэкэнде, в базе? Я понимаю, что "вот тебе json, дальше делай что хочешь". Но как, например, быть с поиском по записям? Выходит, что либо надо под поиск делать отдельную таблицу с "чистыми" данными. Либо под каждую сущность из json делать чуть ли не отдельные таблицы и в еще одной их связывать.
Я в общем не спора ради, а просто узнать мнение пишу. Спасибо.

Ответить
Развернуть ветку
Alexander Menshikov

JSON на стороне бэкэнда действительно нужно дополнительно обрабатывать. Если у вас реляционная БД – скорее всего придётся вытаскивать данные из JSON и сохранять их отдельно. С MongoDB, например, будет проще. Если вам нужен именно поиск – текстовые данные на этапе сохранения можно складывать в ElasticSearch, а JSON целиком хранить где угодно (хоть в столбце MySQL).
Блоки в любом случае придётся обрабатывать для санитайза и для рендеринга. Мы используем для этой задачи отдельную библиотеку (пока что только на PHP): https://github.com/editor-js/editorjs-php

Ответить
Развернуть ветку
Алексей Козлов

С данными в виде JSON прекрасно работает PostgreSQL, для хранения там есть специальный тип JSONB. Более того, оно даже индексируется в таком виде по отдельным узлам.

Ответить
Развернуть ветку
Alexey Poimtsev

Я так понимаю - поддержки markdown нет?

Ответить
Развернуть ветку
Сергей Сильченко

есть кто поможет установить это чудо , junioru(

Ответить
Развернуть ветку
Fedor Dyachkov PM

Один из лучших редакторов

Ответить
Развернуть ветку
Андрей Мирный

Редактор может быть и хороший, только установить его нереально, инструкций нет на русском. Нетратье свое время. 

Ответить
Развернуть ветку
23 комментария
Раскрывать всегда