Slack переводит свой веб-клиент на React. Когда Slack был впервые построен, наш интерфейс состоял из устоявшихся технологий, таких как jQuery и Handlebars. С тех пор сообщество разработало более эффективные способы создания масштабируемых интерфейсов, управляемых данными. Подход jQuery «рендеринг и изменение» прост, но он склонен к рассинхронизации с базовой моделью. В отличие от этого, шаблон React «рендеринг и повторный рендеринг» по умолчанию делает согласованность. Slack развивается вместе с отраслью, чтобы повысить производительность и надежность.

Мы определили, что лучший способ внедрить React - это перестроить существующую функцию продукта - таким образом мы сможем сравнить процесс разработки и конечный результат с известной величиной. Нам нужен был компонент, который был бы интерактивным, автономным и достаточно требовательным, чтобы подтвердить наше предположение о том, что React может улучшить производительность. Не потребовалось много времени, чтобы найти идеального кандидата - широко используемого и удивительно сложного Emoji Picker.

Виртуальная модель DOM с реальными преимуществами

Этот пост предполагает некоторое знание React. Если вы с ним не знакомы, я бы посоветовал просмотреть официальную документацию. Вкратце, React - это библиотека JavaScript, которая упрощает создание декларативных пользовательских интерфейсов, управляемых данными. API урезан и состоит в основном из класса Component, который включает несколько методов жизненного цикла. Компоненты не создают разметку сами по себе. Вместо этого они визуализируются в дерево, подобное DOM, которое называется Virtual DOM. React может сравнить два дерева Virtual DOM, чтобы определить наименьшее количество действий, необходимых для преобразования первого дерева во второе. Например, вы можете указать React повторно отрисовать все представление с новыми данными модели, и он может определить, что ему нужно обновить только текст нескольких узлов. React похож на армию гномов, которые делают специальные обновления DOM от вашего имени.

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

  • Определите идентификатор измененного канала и непрочитанное состояние.
  • Запросите в DOM элемент канала, используя идентификатор канала
  • Переключить непрочитанный класс на элемент канала

Процесс прост, но вам придется написать дополнительные обработчики для поддержки других событий канала, таких как «создание», «присоединение», «выход» и «переименование». Напротив, React поддерживает все пять сценариев с:

  • Повторно отобразите боковую панель канала с новыми данными модели

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

Выбор сборщика

Emoji - неотъемлемая часть пользовательского интерфейса Slack, а Emoji Picker - идеальный компонент React. Он динамичный, дискретный и требует всего нескольких входных данных - списка смайлов, предпочтительного оттенка кожи и истории использования смайликов пользователем. По совпадению, текущий Emoji Picker нуждался в настройке производительности из-за неудачной стратегии рендеринга всех эмодзи независимо от того, был ли он в поле зрения. Поиск включал в себя переключение видимости каждого узла, который соответствует или не соответствует поисковым запросам пользователя. Это была смерть спектакля из-за тысячи сокращений. Новые команды Slack начинаются с 1374 смайликов по умолчанию, и их количество увеличивается по мере того, как вы добавляете обычаи (на момент написания этой статьи у команды Slack всего 3126 смайлов, но у некоторых команд даже больше!) Восстановление средства выбора смайлов даст нам возможность повлиять на повседневное использование Slack осмысленно.

Мы выбрали Storybook, самопровозглашенную среду разработки пользовательского интерфейса, которую вы будете использовать. Он не заменяет ваше руководство по стилю, но делает разработку, тестирование и анализ кода более приятными. Storybook позволяет вам определять варианты вашего компонента, задавая различные наборы свойств. Для средства выбора эмодзи мы добавили вариант для предпочтения тона кожи и несколько вариантов для поиска. Любой в Slack - разработчик или кто-то другой - может открыть Storybook и просмотреть перечисленные состояния.

Компоновка компонентов

React Emoji Picker построен из корневого компонента с отслеживанием состояния и множества дочерних элементов без состояния. Мы придерживались соглашения об экспорте одного компонента в файл. Общая структура следующая:

Заголовок

  • Вкладки категорий: список категорий смайлов со ссылками для перехода.
  • Панель поиска: фильтрует содержимое списка эмодзи по имени / псевдониму эмодзи.

Тело

  • Закрепленный заголовок: отображает название активной категории.
  • Список эмодзи: виртуальный список эмодзи во всех категориях

Нижний колонтитул

  • Предварительный просмотр эмодзи: увеличенное изображение выбранного в данный момент эмодзи
  • Средство выбора оттенка кожи: отображает активный оттенок кожи с возможностью выбора нового.
  • Удобные реакции (необязательно): подмножество смайлов, обычно используемых для реакции на сообщения.

В React есть 2 основных метода написания компонентов без состояния: класс PureComponent и функции. Функции проще, но они отображаются при каждом согласовании, что может снизить производительность. У команды React есть планы по оптимизации функций, но пока, кажется, лучше их избегать. Вместо этого мы решили использовать PureComponent, который включает предопределенный метод shouldComponentUpdate, который предотвращает обновления при передаче идентичных свойств.

Поскольку React - это просто уровень представления, включение его в устоявшееся приложение может быть более простым, чем интеграция предписывающей структуры. Для нас было важно не пойти на компромисс с инкапсулированным дизайном нового Emoji Picker, чтобы учесть шаблоны, существующие в Slack - мы хотели, чтобы компонент выглядел так, как будто он был взят из сквозного приложения React. Чтобы сборщик оставался чистым, мы создали облегченный адаптер в нашей существующей модульной системе. Адаптер устанавливает компонент, извлекает данные модели и прослушивает внешние сигналы. Этот шаблон позволяет нам постепенно переносить кодовую базу, пока мы разрабатываем новые функции.

Новый рабочий процесс разработки

Хотя разработка с помощью React была радостью, интегрировать ее в наш ранее существовавший рабочий процесс разработки не было - по крайней мере, поначалу. В то время конвейер сборки внешнего интерфейса Slack был разработан собственными силами и не имел понятия об импорте, зависимостях или сложных преобразованиях, таких как транспиляция. Однако мы были полны решимости в полной мере использовать синтаксис JSX, а также преимущества написания ES2015 + JavaScript. Вместо современного конвейера сборки мы начали с локальной сборки ресурсов Emoji Picker с помощью Babel и webpack.

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

  • Разработал службу на основе webpack-dev-server для автоматической компиляции и обслуживания ресурсов на наших серверах разработки при изменении наблюдаемых файлов или их зависимостей (включая собственную конфигурацию webpack).
  • Добавлена ​​поддержка загрузки ресурсов веб-пакета в модульные тесты (что позволяет писать тесты для наших компонентов React)
  • Переработан процесс производственной сборки, чтобы размещать ресурсы webpack в нашей CDN.

Перестройка Emoji Picker оказалась именно тем импульсом, который нам нужен для переосмысления нашего конвейера сборки, чтобы объединять и переносить активы более надежным и масштабируемым способом.

Результаты производительности

Мы развернули новый компонент в небольшом количестве команд и наблюдали за результатами. Мы измерили скорость рендеринга по 5 распространенным способам взаимодействия пользователей с Emoji Picker. Реализация React была заметно быстрее для большинства действий. Ниже перечислены различия во времени рендеринга для команды обычного размера:

  • Первое подключение: -270 мс (уменьшение на 85%)
  • Второе крепление: -158 мс (уменьшение на 91,3%)
  • Поиск (много результатов): + 27 мс (увеличение на 259%)
  • Поиск (один результат): -25 мс (уменьшение на 53,2%)
  • Сбросить поиск: -68 мс (уменьшение на 70,1%)

Наибольшее улучшение произошло во время Первого монтирования, которое упало на 270 мс с 318 мс до 48 мс, то есть на 85%. Это в значительной степени связано с react-virtualized - библиотекой виртуальных списков - которая уменьшила количество отображаемых эмодзи. React Emoji Picker отображает на 85% меньше узлов DOM в представлении по умолчанию.

Возможно, самое удивительное изменение произошло во время «Поиска (много результатов)», который увеличился на 27 мс с 17 до 44 мс. Устаревшее средство выбора визуально скрывало смайлы, которые не соответствовали поисковому запросу, что означает, что оно относительно быстро, когда почти все соответствует. Об этой обратной стороне этого подхода свидетельствуют сценарии «Поиск (один результат)» и «Сбросить поиск», которые заставляют устаревшее средство выбора выполнять работу с большим набором эмодзи.

Следующие шаги

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

Хотите помочь Slack решить сложные проблемы и присоединиться к нашей растущей команде? Ознакомьтесь со всеми нашими инженерными вакансиями и подайте заявку сегодня.