Обзор
От переводчика: Оригинал статьи
Вступление
Деплой на Heroku Rails приложения которое использует Webpack требует некоторых хитростей, так как для этого нужны одновременно и Ruby, и Node.js. После нескольких неудачных попыток, я нашел решение которое работает без кастомизации билдпаков (buildpacks) Heroku. Если вы знаете как работают билдпаки Heroku, можете прочитать только резюме для TL;DR версии.
Для начала небольшая вводная. Приложение, над которым я работаю, использует React
для отрисовки интерактивных компонентов на фронтенде. Rails обрабатывает роутинг и общается с базой данных. Компоненты React написаны на синтаксисе ES6 который транспилируется в более широко используемый ES5 API с помощью Babel. Также я использую ESLint и Redux. Все модули JavaScript собираются в один файл при помощи Webpack.
Транспилер - компилятор, транслирующий исходный код на одном языке программирования в исходный код на другом языке программирования или более раннюю версию того же языка
Стоит отметить, что есть хорошо поддерживаемый гем react-rails, но мы выбрали npm
, потому что хотели использовать последние версии пакетов React, Redux, ESLint и чувствовали что рабочий процесс (workflow) с npm-based управлением пакетов подойдет лучше в данном случае.
Вот структура проекта с которой мы решили работать:
Первоначально, package.json
требуемый для npm был помещен в каталоге webpack/
, но это усложнило деплой на Heroku. После компиляции Webpack весь JavaScript собирается в файле react_bundle.js
и кладется в каталог app/assets/javascripts
. Этот файл в свою очередь загружается через asset pipeline. Собранный файл должен лежать на своем месте до того как запустится assets:precompile
в процессе деплоя.
Билдпаки Heroku
Heroku использует установочные скрипты, которые они назвали buildpacks, для определения типа приложения и запуска необходимых шагов для деплоя. Например, Heroku запускает сборку и деплой Rack-based приложения если видит файл Gemfile
в корне приложения. Если при этом в списке гемов будут рельсовые то запустится сборка и деплой Rails приложения. Упрощенно, для запуска Rack приложения нужны следующие шаги:
- Поиск
Gemfile
иGemfile.lock
в корневой директории. Если такие есть то предполагаем что это Ruby приложение и стартуем соответствующие задачи. - Проверка что в
Gemfile.lock
есть Rack. - Установка требуемой версии Ruby
- Установка bundler’а и всех зависимостей
- Запуск web сервера на основании
Procfile
или веб сервера по умолчанию
Таким же образом Heroku выполняет шаги для Node.js приложений, основываясь на наличии файла package.json
в корневой директории. Итак, что же делать если нам нужна сборка и Ruby и Node.js одновременно? Нужно чтобы и Gemfile
, и package.json
присутствовали в корневой директории. Это шаг №1.
Множественные билдпаки Heroku
Heroku поддерживает множественные билдпаки для одного приложения. Если у нас Node.js и Ruby билдпаки, то нужен способ указать Heroku, что сначала нужно выполнить сборку для npm и только потом запускать сборку Ruby. Это нужно для того, чтобы файл react_bundle.js
был на своем месте в app/assets/javascripts
до того как запустится сборка assets в Rails. Командная строка Heroku дает нам способ задавать билдпаки и указывать порядок в котором они должны запускаться:
Аргумент --index
означает что heroku/ruby
билдпак добавляется после heroku/nodejs
. Это завершает шаг №2.
Отправка билд хука на Heroku
После того как билдпаки установлены, нам нужен способ запустить команду Webpack сразу после того как Node.js собран, но до того как будет начата сборка Ruby/Rails. Билдпак для Node.js поддерживает способ выполнить кастомный скрипт сразу после того как сборка Node.js прошла. Для этого команда должна быть указана в package.json
внутри секции scripts
c ключом heroku-postbuild
. Вот пример актуальной секции scripts
из package.json
:
На этом заканчивается шаг №3. Благодаря этим 3 шагам, я смог построить работающий процесс деплоя для Rails + Webpack приложения.
Резюме
- Поместите
package.json
в корневом каталоге вашего Rails приложения. - Настройте множественные билдпаки на Heroku через утилиту командной строки так, чтобы
heroku/nodejs
был на первом месте аheroku/ruby
втором. - Добавьте Webpack команду для сборки бандла в секцию
scripts
файлаpackage.json
с ключомheroku-postbuild
.