Деплой webpack-приложения на github.io с помощью Travis CI +16

Задача


Есть приложение, сгенерированное с помощью 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
    /#11373774

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


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

    • Nondv
      /#11373790

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

      • justboris
        /#11373797

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


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

        • Nondv
          /#11378077

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


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

          • justboris
            /#11498415

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


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


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

            • Nondv
              /#11608095

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


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


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

              • m8rge
                /#16003145

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

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

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

                • Nondv
                  /#16024443

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


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


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

  2. acsent1
    /#11378121

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

    • Nondv
      /#11387041

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


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


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

      • kinjalik
        /#16014189

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

        • Nondv
          /#16014429

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

          • kinjalik
            /#16160203

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

            • mayorovp
              /#16187415

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

              • kinjalik
                /#16690993

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

                • mayorovp
                  /#16697585

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

                  • kinjalik
                    /#16703373

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

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

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

                    • Nondv
                      /#16965915 / +1

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


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

  3. akurilov
    /#12932177 / +1

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

  4. Nezd
    /#14853997 / +1

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

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

    • Nondv
      /#15218341

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


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


      Спасибо!