Задача


Есть приложение, сгенерированное с помощью create-react-app. Нужно развернуть его на github.io.


Проблемой является то, что Github Pages работает только со статическим кодом и Jekyll.


Решение


Разумеется, нам достаточно просто скомпилировать приложение где-нибудь в другом месте и уже потом выкладывать на github.io


Для этой задачи идеально подошел Travis CI, т.к. как выяснилось, у него есть возможность деплоя на гитхаб из коробки (не нужно изгаляться и писать сложные скрипты для этого).


Я завел два репозитория:


  • Код приложения
  • Репозиторий со скомпилированной версией, который и использует github.io

Как происходит ручной деплой


  1. Компилируем код (yarn build)
  2. В папке второго репозитория делаем git rm -r . — это удалит все файлы (кэп).
  3. Копируем скомпилированный код во второй репозиторий (cp -r build/ ../compiled-app)
  4. git add .
  5. git commit
  6. 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.com
  • keep-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)


  1. justboris
    27.05.2018 14:31

    Если положить файл CNAME в папку public, то react-scripts скопируют его в build при сборке.


    Так можно избавиться от костыля с echo.


    1. Nondv Автор
      27.05.2018 15:02

      Думал об этом. Но тогда будет костыль с лежащим в public/ (я думал, что лучше в build/ и под гит занести) файлом CNAME, а так все, что относится к деплою хотя бы хранится в одном конфиге, я считаю это меньшим из зол. Остальному коду должно быть плевать на деплой


      1. justboris
        27.05.2018 15:33

        Папка public предназначена для любых файлов, которые должны оказаться в корне сайта. В документации react-scripts есть список примеров, что туда можно положить.


        Файл CNAME вполне подходит по критерию "You need a file with a specific name in the build output".


        1. Nondv Автор
          27.05.2018 15:35

          не соглашусь.
          Мне не нужен файл CNAME на моем сайте. Мне он нужен в репозитории github, чтобы github pages адекватно работал с доменом.


          Приложение может быть задеплоено и в другом месте. Так что в public/ на мой взгляд этому файлу точно делать нечего


          1. justboris
            27.05.2018 16:15

            Нашел интересную ссылку: https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#step-5-optionally-configure-the-domain


            Официальная документация советует делать именно так — через public folder.


            В своем проекте вы можете делать как вам удобно, но если работать в команде — то ваше ноу-хау принесет боли программистам, которые не будут понимать откуда берется файл, если его нет.


            1. Nondv Автор
              27.05.2018 16:32

              Я ответил Вам, почему считаю такой подход неразумным.


              Мой код не должен знать что-то о тонкостях хостинга и зависеть от него. CNAME — это черта исключительно github.io, соответственно, она должна находиться только в коде, осуществляющим деплой.


              Anyway, я считаю оба варианта костыльными, так что кому что


              1. m8rge
                28.05.2018 12:31

                К тому-же, файл не доступен через http:

                github.com/m8rge/webpage/blob/gh-pages/CNAME
                aputilov.ru/CNAME — 404

                Делайте как в документации, не придумывайте ненужных велосипедов =)


                1. Nondv Автор
                  28.05.2018 13:03

                  Для меня документация к утилите, генерирующей проект (не фреймворк), не является авторитетом.


                  Директория public используется многими фреймворками и должна использоваться для хранения статических файлов, которые должны быть доступны "as is" для отдачи сервером. В пример можно привести рельсы и express (хотя там название все же опционально). Вы же предлагаете там хранить файлы конфигурации хостинга. Подход с добавлением файла в public проще, но все так же является костылем. И то, что об этом написано в документации (причем документации к утилите), этого не отменяет


                  Не понимаю, зачем Вы продолжаете этот тред.


  1. acsent1
    27.05.2018 15:36

    Есть же пакет gh-pages
    Всю описаную работу он делает сам


    1. Nondv Автор
      27.05.2018 15:38

      Спасибо за наводку!


      Быстро сейчас глянул. Как я понял, он нужен для деплоя с локальной машины. У меня же деплой происходит через CI.


      Т.е. от меня требуется просто запушить изменения в мастер, CI запустит тесты, билд и если все ок, то задеплоит уже на github.io


      1. kinjalik
        28.05.2018 12:51

        У меня через этот пакет идёт деплой с Gitlab CI. Ну и от этого у меня появляется возможность использовать Gitlab Pages как промежуточный вариант


        1. Nondv Автор
          28.05.2018 12:51

          как видите, в тревисе этот функционал есть из коробки=)


          1. kinjalik
            28.05.2018 15:07

            +1 зависимость от стороннего сервиса. Плюс GitLab-а — его можно развернуть на своем сервере. А можно отдельно у себя разместить приватный раннер для GitLab CI, и потому не зависеть от внешних CI-сервисов


            1. mayorovp
              28.05.2018 15:27

              Сам по себе GitLab является таким же сторонним сервисом. А «своего сервера» у человека, который использует github pages, может и не быть вовсе.


              1. kinjalik
                28.05.2018 19:12

                Да, но ничто не запрещает запустить на своем сервере свой GitLab (напомню, GitLab распространяется бесплатно, и каждый может его у себя поднять)


                1. mayorovp
                  28.05.2018 19:14

                  Это только когда свой сервер есть.


                  1. kinjalik
                    28.05.2018 19:17

                    Похоже, мы не так друг друга поняли.

                    Моя точка зрения: Travis CI — +1 сервис, от работы которого зависит проект
                    Добавим к нему GitHub — уже 2 сервиса. Один не работает — и все встало.

                    В альтернативу я предлагаю GitLab, который предлагает либо не зависеть от сторонних сервисов вообще (сам устанавливаешь к себе), либо, если и зависеть, то только от одного сервиса


                    1. Nondv Автор
                      28.05.2018 20:34
                      +1

                      с таким же успехом можно деплоить и с локальной машины, с помощью скриптов. В чем смысл вашего подхода? В том, что тревис неожиданно упасть может? Это смех


                      Смысл поста в том, чтобы продемонстрировать, что веб-приложения с гитхаба могут "изкаробки" деплоиться на pages с помощью бесплатного и известного travis ci


  1. akurilov
    27.05.2018 19:07
    +1

    Я сначала в заголовке прочитал "долой" вместо "деплой" и заинтересовался


  1. Nezd
    27.05.2018 23:32
    +1

    Если не используется custom domain, то сайт будет находиться по адресу yourname.github.io/projectname, и тем самым у меня ломались абсолютные пути (например, /favicon.ico). Я не стал думать над решением, т.к. у меня используется отдельный домен.

    Если в package.json добавить «homepage»:"./", то все пути до статики в «сбилженом» index.html будут относительно текущей папки.


    1. Nondv Автор
      28.05.2018 00:39

      Да, все верно. При билде даже выводится сообщение, говорящее об этом.
      Но лично меня это не спасло в некоторых случаях (однако вина была полностью на мне, следует полагать).


      В любом случае, с этой проблемой можно столкнуться и следует держать это в уме.


      Спасибо!