Задача
Есть приложение, сгенерированное с помощью create-react-app
. Нужно развернуть его на github.io.
Проблемой является то, что Github Pages работает только со статическим кодом и Jekyll.
Решение
Разумеется, нам достаточно просто скомпилировать приложение где-нибудь в другом месте и уже потом выкладывать на github.io
Для этой задачи идеально подошел Travis CI, т.к. как выяснилось, у него есть возможность деплоя на гитхаб из коробки (не нужно изгаляться и писать сложные скрипты для этого).
Я завел два репозитория:
- Код приложения
- Репозиторий со скомпилированной версией, который и использует github.io
Как происходит ручной деплой
- Компилируем код (
yarn build
) - В папке второго репозитория делаем
git rm -r .
— это удалит все файлы (кэп). - Копируем скомпилированный код во второй репозиторий (
cp -r build/ ../compiled-app
) git add .
git commit
git push
.travis.yml
language: node_js
node_js:
- '9.11'
cache:
directories:
- "node_modules"
script:
- yarn test
- yarn build
- echo my-custom-domain.ru > build/CNAME
deploy:
provider: pages
github-token: $GITHUB_TOKEN # Set in the settings page of your repository, as a secure variable
committer-from-gh: true
skip-cleanup: true
keep-history: true
local-dir: build
repo: Yourname/compiled-app
target-branch: master
on:
branch: master
Пояснения:
- В разделе script можно увидеть странное echo. Это костыль нужен для сайтов с собственным доменом, т.к. github использует файл CNAME для хранения этой настройки (уж не знаю, почему). Т.к. весь текущий код репозитория будет удален, то и этот файл не сохранится.
github-token
— его нужно сгенерировать в настройках гитхаба. Подробнее здесь. Переменную окружения нужно задать в настройках проекта на travis-ci.comkeep-history
— без этой опции репозиторий по сути будет создаваться каждый раз заново (push -f) и отследить историю будет невозможно. С ним же все будет покоммитно (примерно как я описал это в разделе "ручной деплой").local-dir
— после того, как билд отработал, тревису нужно знать, что именно сохранять в репозиторий. Без этой опции он сохранит весь текущий код, а с ней — определенную папку. Сохранять полностью проект может быть полезно, если вы не хотите использовать два репозитория, как я, а использовать папкуdocs/
или отдельную ветку, не связанную с кодом.repo
— это именно та опция, которая позволяет деплой в другой репозиторий. Не забывайте указывать владельца.target-branch
— в какую ветку именно должен происходить пуш. По-умолчаниюgh-pages
, я использую master, т.к. у меня это отдельный репозиторий.
Возможные проблемы
Лично я столкнулся только с одной проблемой.
Если не используется custom domain, то сайт будет находиться по адресу yourname.github.io/projectname
, и тем самым у меня ломались абсолютные пути (например, /favicon.ico
). Я не стал думать над решением, т.к. у меня используется отдельный домен.
Документация
Заключение
Я обожаю github.io и давно хотел поковырять, можно ли туда деплоить компилируемые сайты кроме Jekyll. Было очень приятно обнаружить, что в travis-ci об этом уже подумали.
Еще я сегодня подумал, что возможно лучше было бы не создавать отдельный репозиторий, а просто использовать отдельную ветку. Чтобы не засорять мой список репозиториев, который и так наполнен всяким мусором. Ну, как говорится, c'est la vie
Offtop для тех, кому интересно, что именно я делал
Я играю в игру Heroes of the Storm и хотел сделать небольшое приложение, которое упростило бы для меня выбор персонажа во время драфта. Если короче: фильтр героев по их особенностям.
Комментарии (21)
acsent1
27.05.2018 15:36Есть же пакет gh-pages
Всю описаную работу он делает самNondv Автор
27.05.2018 15:38Спасибо за наводку!
Быстро сейчас глянул. Как я понял, он нужен для деплоя с локальной машины. У меня же деплой происходит через CI.
Т.е. от меня требуется просто запушить изменения в мастер, CI запустит тесты, билд и если все ок, то задеплоит уже на github.io
kinjalik
28.05.2018 12:51У меня через этот пакет идёт деплой с Gitlab CI. Ну и от этого у меня появляется возможность использовать Gitlab Pages как промежуточный вариант
Nondv Автор
28.05.2018 12:51как видите, в тревисе этот функционал есть из коробки=)
kinjalik
28.05.2018 15:07+1 зависимость от стороннего сервиса. Плюс GitLab-а — его можно развернуть на своем сервере. А можно отдельно у себя разместить приватный раннер для GitLab CI, и потому не зависеть от внешних CI-сервисов
mayorovp
28.05.2018 15:27Сам по себе GitLab является таким же сторонним сервисом. А «своего сервера» у человека, который использует github pages, может и не быть вовсе.
kinjalik
28.05.2018 19:12Да, но ничто не запрещает запустить на своем сервере свой GitLab (напомню, GitLab распространяется бесплатно, и каждый может его у себя поднять)
mayorovp
28.05.2018 19:14Это только когда свой сервер есть.
kinjalik
28.05.2018 19:17Похоже, мы не так друг друга поняли.
Моя точка зрения: Travis CI — +1 сервис, от работы которого зависит проект
Добавим к нему GitHub — уже 2 сервиса. Один не работает — и все встало.
В альтернативу я предлагаю GitLab, который предлагает либо не зависеть от сторонних сервисов вообще (сам устанавливаешь к себе), либо, если и зависеть, то только от одного сервисаNondv Автор
28.05.2018 20:34+1с таким же успехом можно деплоить и с локальной машины, с помощью скриптов. В чем смысл вашего подхода? В том, что тревис неожиданно упасть может? Это смех
Смысл поста в том, чтобы продемонстрировать, что веб-приложения с гитхаба могут "изкаробки" деплоиться на pages с помощью бесплатного и известного travis ci
Nezd
27.05.2018 23:32+1Если не используется custom domain, то сайт будет находиться по адресу yourname.github.io/projectname, и тем самым у меня ломались абсолютные пути (например, /favicon.ico). Я не стал думать над решением, т.к. у меня используется отдельный домен.
Если в package.json добавить «homepage»:"./", то все пути до статики в «сбилженом» index.html будут относительно текущей папки.Nondv Автор
28.05.2018 00:39Да, все верно. При билде даже выводится сообщение, говорящее об этом.
Но лично меня это не спасло в некоторых случаях (однако вина была полностью на мне, следует полагать).
В любом случае, с этой проблемой можно столкнуться и следует держать это в уме.
Спасибо!
justboris
Если положить файл CNAME в папку public, то react-scripts скопируют его в build при сборке.
Так можно избавиться от костыля с echo.
Nondv Автор
Думал об этом. Но тогда будет костыль с лежащим в
public/
(я думал, что лучше вbuild/
и под гит занести) файлом CNAME, а так все, что относится к деплою хотя бы хранится в одном конфиге, я считаю это меньшим из зол. Остальному коду должно быть плевать на деплойjustboris
Папка public предназначена для любых файлов, которые должны оказаться в корне сайта. В документации react-scripts есть список примеров, что туда можно положить.
Файл CNAME вполне подходит по критерию "You need a file with a specific name in the build output".
Nondv Автор
не соглашусь.
Мне не нужен файл CNAME на моем сайте. Мне он нужен в репозитории github, чтобы github pages адекватно работал с доменом.
Приложение может быть задеплоено и в другом месте. Так что в
public/
на мой взгляд этому файлу точно делать нечегоjustboris
Нашел интересную ссылку: https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#step-5-optionally-configure-the-domain
Официальная документация советует делать именно так — через public folder.
В своем проекте вы можете делать как вам удобно, но если работать в команде — то ваше ноу-хау принесет боли программистам, которые не будут понимать откуда берется файл, если его нет.
Nondv Автор
Я ответил Вам, почему считаю такой подход неразумным.
Мой код не должен знать что-то о тонкостях хостинга и зависеть от него. CNAME — это черта исключительно github.io, соответственно, она должна находиться только в коде, осуществляющим деплой.
Anyway, я считаю оба варианта костыльными, так что кому что
m8rge
К тому-же, файл не доступен через http:
github.com/m8rge/webpage/blob/gh-pages/CNAME
aputilov.ru/CNAME — 404
Делайте как в документации, не придумывайте ненужных велосипедов =)
Nondv Автор
Для меня документация к утилите, генерирующей проект (не фреймворк), не является авторитетом.
Директория public используется многими фреймворками и должна использоваться для хранения статических файлов, которые должны быть доступны "as is" для отдачи сервером. В пример можно привести рельсы и express (хотя там название все же опционально). Вы же предлагаете там хранить файлы конфигурации хостинга. Подход с добавлением файла в public проще, но все так же является костылем. И то, что об этом написано в документации (причем документации к утилите), этого не отменяет
Не понимаю, зачем Вы продолжаете этот тред.