Использование React в качестве интерфейса для Rails

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

В этой ситуации использование React было довольно очевидным выбором; поскольку я хотел заменить только слой представления, фреймворк вроде Angular или Ember мог быть слишком большим, в то время как React ориентирован только на ту часть, которую я хотел заменить. Итак, я сделал первый шаг, заменив некоторые файлы .erb компонентами React.

React Rails

Вначале я был сосредоточен только на создании компонентов React, которые напрямую заменяли непосредственную функциональность существующих компонентов .erb, и, к счастью, гем react-rails сделал именно это. Кроме того, гем позволил нам использовать React с es2016 (es6), который имеет совершенно другой и новый синтаксис. Заменив некоторые фрагменты представления на чистый React, мы смогли удалить большинство запросов, генерирующих серверную часть пользовательского интерфейса, и вместо этого использовать компоненты React для использования конечных точек API для получения информации после рендеринга. Сделав это на главной странице, мы смогли сократить время загрузки страницы вдвое.

Вот пример некоторых из внесенных мной изменений:

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

Однако мы хотели начать использовать некоторые уже существующие компоненты React, и именно здесь началось самое интересное.

NPM + CommonJS

Большинство библиотек React живут на NPM, поэтому мы хотели попробовать интегрировать это в наш стек. Изначально у нас с этим были некоторые проблемы, поэтому мы нашли действительно хакерский обходной путь. Вместо того, чтобы полагаться на NPM для обработки зависимостей, мы:

  1. Загрузите репозиторий библиотеки на github
  2. Измените их код, чтобы удалить все ссылки на внешние библиотеки.
  3. Запустите на нем browserify, чтобы создать единый комплект, который мы могли бы добавить к системе, требующей звездочек.
  4. Загрузите все зависимые библиотеки и сделайте то же самое, пока все зависимости не будут удовлетворены.

Это стало отстойным очень быстро, поэтому мы решили перекусить и перейти на CommonJS. К счастью, нам в этом поможет жемчужина browserify-rails.

Перво-наперво, мы добавили browserify-rails в наш Gemfile, а затем добавили package.json, который содержал все наши ранее добавленные клиентские зависимости. Нам пришлось отказаться от звездочек, чтобы скомпилировать наши реагирующие компоненты, поэтому нам также пришлось добавить конфигурацию для ее создания. Вот как выглядит наш файл package.json:

  • babel зависимости предназначены для нового конвейера сборки
  • browserify требуется для browserify-rails
  • React и react-dom необходимы нам для замены конвейера сборки react-rails

Первым шагом была настройка browserify для компиляции наших ресурсов React. Поскольку мы используем es2016, нам также пришлось настроить его для его компиляции. Раньше пакет npm reactify был предпочтительным способом сделать это; однако недавно response переключился на компиляцию с помощью babel. Babel также только что выпустил версию 6.0.0, в которой изменился способ построения конвейера, то есть нам пришлось использовать плагины. К счастью, для es2015 и для реакции были предустановки плагинов, так что это было так же просто, как их использовать. Вот как выглядела конфигурация, когда мы закончили:

После этого мы изменили наш components.js (ранее добавленный для react-rails) на что-то вроде следующего:

Здесь нам требуются React и ReactDOM, что позволяет нам продолжать использовать их в глобальном масштабе, а также требуются компоненты, которые требуются в глобальной области. Это необходимо для того, чтобы react-rails продолжал вызывать response_component для монтирования реагирующих компонентов.

Следующее, что мы сделали, - переместили все наши компоненты из component.es6.jsx в component.jsx и получили их:

  1. экспортировать свой модуль
  2. импортировать все зависимые модули

Вот пример того, как выглядел компонент, когда мы закончили

Как только мы со всем этим разобрались, мы почти закончили! Теперь все, что нам нужно было сделать, это выяснить, как его развернуть.

Развертывание на Heroku

Развернуть на Heroku довольно просто; все, что нам нужно сделать, это убедиться, что npm install вызывается, чтобы мы получили все наши внешние ресурсы и просмотрели для сборки. Для этого нам просто нужно добавить buildpack узла в нашу среду в дополнение к buildpack rails.

Развертывание на Elastic Beanstalk

К сожалению для нас, мы только что перешли с Heroku на AWS Elastic Beanstalk. EB делает для нас много замечательных вещей из коробки, но npm install не входит в их число. Кроме того, он также пытается запустить rake precompile: assets, который отлично подходит для начальной загрузки, но это также означает, что перед этим необходимо запустить npm install. Для борьбы с этим мы добавили файл конфигурации .ebextension.

Здесь мы создаем обработчик pre-appdeploy, который запускается на шаге 9 и запускает npm install, если файл package.json существует. Шаг 9 был для нас довольно важным, поскольку bundle install вызывается на шаге 10, а rake precompile: assets - на шаге 11.

После этого мы смогли развернуть eb, и все заработало!