ONEHOPE выпустила нашу платформу электронной коммерции, построенную на React, Relay, GraphQL, FlowType и NodeJS, в январе 2017 года.

Мы выбрали GraphQL, потому что мы управляем более чем 14 микросервисами NodeJS в кластере распределенных систем, и нам нужен был разумный способ доступа к этим микросервисам. GraphQL предоставляет нам следующее:

  1. Действует как шлюз API для этих сервисов.
  2. Организует полезные нагрузки сервера и применяет к ним преобразования данных для использования нашим клиентским интерфейсом.
  3. Предоставляет документацию по данным API через GraphiQL
  4. Мягкое устаревание API и полей API, что позволяет нам быстро и безопасно выполнять итерации на нашем бэкэнде.

Как ни странно, опыт разработчиков Relay/GraphQL лучше, чем Redux. Relay дает нам множество бесплатных выигрышей и готовых функций, таких как:

  • Оптимистичные обновления. Relay позволяет нам вносить локальные изменения в хранилище при условии, что наш вызов API завершится успешно. Это позволяет нам немедленно обновить пользовательский интерфейс, ожидая ответа сервера.
  • Извлечение только того, что нужно компоненту разумным способом. Frontend-разработчики никогда не ломали голову над тем, как преобразовать данные сервера, чтобы они соответствовали требованиям к данным компонентов React. GraphQL и Relay сделали это за нас.
  • Совместное размещение требований к данным и представлений React, которые дают разработчикам более четкое понимание и постоянную предсказуемость того, как компонент React взаимодействует со всей системой. Мы точно знаем, какой компонент React изменится из-за изменения бэкэнда или GraphQL. С клиентами, подключенными к REST API, вы не узнаете, какие страницы вышли из строя из-за изменения полезной нагрузки API, если только у вас нет тщательного тестового покрытия.
  • Безопасность типов данных на стороне клиента с помощью фрагментов ретрансляции, основанных на типизированной схеме GraphQL.
  • Для передачи серверных данных в компоненты React нужно было написать гораздо меньше стандартного кода по сравнению с Redux.

Когда я взглянул на новый Relay Modern API, я был в восторге.

В экосистеме GraphQL есть понятие «мутации», именно так пишут в системе, использующей GraphQL. Одна из больших побед заключается в том, что мутации в Relay Modern писать было проще, чем в Relay Classic. Больше никаких «толстых запросов» и перегруженных конфигураций мутаторов, чтобы заставить мутацию работать.

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

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

Классические конфигурации мутаторов, такие как RANGE_ADD и FIELDS_CHANGE, сделали внесение изменений в хранилище волшебным и черным ящиком. Modern дает нам детальный контроль над хранилищем Relay, когда происходят мутации через его императивный API.

Реализация современной мутации — это общая победа в опыте разработчиков. Функции проще понять, чем классы ES6. Мутация Modern кажется более подробной, потому что запрос на мутацию (набор данных, запрошенный клиентом на серверной части для выполнения изменения пользовательского интерфейса) должен быть задан явно. Тем не менее, прирост производительности за счет статических запросов стоит того, чтобы обратить внимание на этот незначительный недостаток.

Статические запросы означают, что все запросы GraphQL для приложения определяются заранее. Запросы GraphQL в Relay Modern создаются во время компиляции, а не во время выполнения, как в Classic. Это позволяет резко повысить производительность при выборке запросов и фиксации изменений, поскольку вся работа по вычислению запросов уже выполнена, и клиенту не нужно ее выполнять. Это также открывает возможности для других оптимизаций, таких как постоянные запросы; что уменьшает полезную нагрузку, которую клиент должен отправить, и уменьшает возможности для атак на наши API, поскольку мы можем вносить запросы в белый список на основе хэша, отправляемого по сети.

Процесс

  1. Начал согласно документам
  2. Переключил наше решение маршрутизации с react-router-relay на found
  3. Запускал мод миграция на современный код по одной функции за раз.
  4. Исправьте папку функций ровно настолько, чтобы она отобразилась. Закомментируйте все мутации.
  5. Повторяйте 2 и 3, пока вся кодовая база не будет использовать Modern, и мы не сможем отказаться от Classic.
  6. Вернитесь к каждой папке функций и заставьте ее работать так же, как и в производственной среде, включая ручную переписывание всех мутаций Relay.

Мы не использовали режим совместимости, потому что преобразование классических компонентов в современные заняло очень мало времени. Мы смогли выполнить преобразование, параллельно разрабатывая новые функции.

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

Конверсия была в целом положительной.

Большая достоверность состояния кэша ретрансляции

В прошлом мы часами ломали головы, почему наш классический магазин не обновлялся так, как мы хотели. Мы замусорили наши мутации REQUIRED_CHILDREN в надежде, что это даст нам изменения в нужном нам хранилище. Сочетание возможности явно указать, какие фрагменты GraphQL нам нужны и как это должно повлиять на кеш Relay, позволяет нам создавать более отзывчивый и иммерсивный пользовательский интерфейс, который было трудно создать в Classic; с большей уверенностью, что магазин будет обновляться так, как мы хотим.

Более высокая производительность

Наша современная производственная среда имела:

  • В 1,25-2 раза быстрее начальные сетевые вызовы
  • мутации разрешаются в 3 раза быстрее
  • На 200 мс быстрее начальная краска

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

Мы довольны работой с Relay Modern и рады потенциальным инструментам и функциям, которые можно создать с помощью пакетов graphql-compiler и relay-runtime. С помощью graphql-compiler мы могли бы создать способ генерации типизации TypeScript для компонентов Relay, очень похожий на то, как сегодня он генерирует типизацию Flow. В relay-runtime есть примитивы для автономного кэширования, что открывает возможности для лучшего обслуживания устройств с нестабильным интернетом.

Мы с нетерпением ждем возможности увидеть и внести свой вклад в развитие экосистемы GraphQL и инноваций, которые появятся в клиентах GraphQL.

Ознакомьтесь с нашей платформой электронной коммерции, написанной на Relay Modern здесь!

В восторге от работы с новейшим JavaScript? Присоединяйтесь к нам на ONEHOPE!

Спасибо, Jackie Feiler, Jeong Min Lee и Matt Middlesworth за рецензирование этой записи.