51
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

create-react-appを使ってCI

create-react-appとReact.jsの練習を兼ねてmacのメモっぽい何かを作ってみます。
Facebookのライセンスまわりが炎上しているようですが・・・。
Reactに限らずJavaScriptを使って開発しようとするとwebpack, gulp, babel, Jest等など開発環境整えるのまじ面倒くさい。面倒くさいので一度作るとずっとそのままでいつの間にか古くなっています。
Create React Appはその面倒な環境を一発で整えてしかも自分で作るよりもビルドがなんか速い!
そして、テストツールのJestが組み込まれているのでせっかくなのでCIする環境を構築してみました。

ソース他

GitHub

GitHub Pages

heroku

1. アプリ仕様

macのメモアプリっぽいなにかを作る。
データはlocalStorageへ保存。

2. 構成

変わったことはしないでできるだけ分かりやすく。
ビルドしたアプリはheroku上で見られるようにします。

ci.png

3. 開発環境構築

3.1. node.jsのインストール

公式サイトに行ってv8.2.1をダウンロードしてインストールしました。
npmが5になっています。lockファイルを作る様になっています。

3.2. yarnのインストール

npmが5になっていましたがパッケージ管理ツールはyarnを使います。だってcreate-react-appもyarnもFacebook謹製だし。

npm install -g yarn

3.3. Create React Appのインストール

これもコマンド一発。

npm install -g create-react-app

3.4. アプリを作る

create-react-app memo

これだけで基本的になにもやる必要なし!で、

cd memo
yarn start

をおこなうと、このように表示されます。
yarn-start.png

そうするとブラウザ上でこの様に表示されます。
localhost.png

ローカルマシン上でWebサーバーが起動して更新がリアルタイムで反映されるようになります。webpack-dev-serverが動いている様ですが、ここまで設定するのに一からやったらめっちゃ大変です。

src/index.jsが起点となっています。

src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

src/App.jsなんかをいじると直ぐに反映されます。Reactで書かれていますがReact知らなくても直感的に分かるとおもいます。
cssもimportをインポートしていてビルドするとcssファイルとして出力されます。なにがどうやっているのかは分かりませんがとにかく便利!
ちなみに別にReact使わなくてもいいので開発環境として使うのもありかなと思います。

4. テスト

Jestが入っているので直ぐにテストが書けます。

yarn test

これで実行出来ます。
サンプルがsrc/App.test.jsとして入っています。ファイル名.test.jsのファイルがテストファイルとして見なされます。もしくはsrc/__tests__に入っているjsファイルです。
また、モック用のディレクトリsrc/__mocks__内のファイルもテスト用のファイルと見なされてテスト対象に含まれなくなります。

package.json内の"test": "react-scripts test --env=jsdom"の部分を`"test": "react-scripts test --env=jsdom --coverage"にするとカバレッジ率を出せます。

coverage.png

5. ビルド

yarn build

buildディレクトリが出来てその中にhtml, js, css含めた一式が出力されます。
build.png

serveが入っていない場合はserveいれて〜みたいにいわれます。
yarnなりnpmなりでserveを入れて書いてあるようにserve -s buildでビルド後のファイルをローカルで確認出来ます。
github pagesのことも書かれていますが下の方で解説します。

またjsを動かしているだけならindex.htmlをブラウザに放り込んで確認してもいいのですが、その場合jsやcssなんかのパスの問題が出てきます。index.htmlをいじっただけではだめで、css内の画像へのリンクなんかも問題がでます。その場合package.json内に

{
    "homepage": "./"
}

を追加してビルドすればOKでした。

5.1 ファイルのハッシュが嫌な場合

ビルドするとmain.jsとmain.cssが作られるのですがmain.9fdf0e48.jsの様にそれぞれのファイルのハッシュ値がファイル名につきます。ブラウザキャッシュのことを考えると有用なのですが要らないときもあります。そう言う場合は何かしらハッシュ値をつけないオプションがあるのかなーと探しましたがどうも無いみたいです。ハッシュを削除するには力技でシェルスクリプトで削除するのが良さそうです。

package.jsonのscriptsへpostbuildを追加してそこで削除するシェルスクリプトを実行すればいけます。ファイルをmvしてhtmlをsedする感じでしょうか。

{
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "postbuild": "bash deleteHash.sh",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

preつけたりpostつけたりするとそれぞれの動作の前後で実行してくれます。

あとyarn ejectを行うと create-react-appの管理から抜け出してnode_modules以下に必要なモジュールが全てインストールされて単独で動くようになります。
そうしたら、ハッシュをつけているところを探し出して書き換えればいいんじゃないかなーみたいな。

6. アプリの作成

開発環境がこれで出来たのでmacのメモアプリもどきを作っていきます。
React使うの面倒くさくなって一部jqueryで書いてしまっています・・・。

7. GitHub Pages

herokuへデプロイするのでGitHub Pagesなくてもいいのですがメチャクチャ便利だったので。用途によってはこっちだけで十分です。
GitHub PagesについてのCreate React Appのドキュメントはこちらに書いてあってめっちゃ簡単なのですが少々解説を。

GitHub PagesはGitHubで行っている静的ファイルの公開サービスです。
今回使っているのは
https://taichi0529.github.io/memo/
の様にhttps://ユーザー名.github.io/リポジトリ名/で見ることが出来るサービスのほうです。
リポジトリにgh-pagesってブランチ作ってそこにファイルを置くだけでみることができます。
ただ、ブランチがそのままルートディレクトリになるのでビルドしたファイルでそっくり置き換える必要があります。それをgh-pagesモジュールが全自動でやってくれます。

7.1. gh-pagesモジュールのインストール

yarn add gh-pages

7.2. gh-pagesのブランチをgithub上に作成する

github上でどうやってブランチ作るのかわかりにくかったですが、簡単でした。
branch.png

7.3. package.jsonの設定

手動でビルドした後にgh-pagesでもいいのですが折角なので。

package.json
{
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject",
+   "preghpages": "yarn build",
+   "ghpages": "gh-pages -d build"
  },
+ "homepage": "./"
}

package.jsonのhomepageは./を入れておけば動くと思いますが動かなかったらフルパスで。

7.4. 起動

yarn ghpages

これでGitHub Pagesに公開されます。

8. heroku

Circle CIからherokuへデプロイするのですがローカルからデプロイして動くようにしておいた方が便利なのでそうします。

8.1. herokuアプリの作成

Create New Appで新しいAppを作成します。そうするとこんな画面が出てきます。

deploy.png

この通りやれば簡単にデプロイできるのですが今回はCircle CIからデプロイしたいので少々変えます。herokuコマンドめっちゃ便利なんですけどね。

書いてあるとおりにやるとherokuへのgitがhttps経由になってしまいます。そうするとCircle CI上にもherokuコマンドを使える環境を構築しないといけないので。ただ、Create React Appのドキュメントにあるリンク先はherokuコマンドを使うやり方が書いてありました。

8.2. gitへリモートリポジトリの登録

heroku上のリポジトリへpushすることでデプロイされるのでherokuをリモートリポジトリとして登録します。

git remote add heroku git@heroku.com:[App名].git

.git/configを確認するとherokuが登録されているはずです。

8.3. キーペアの作成及び設定

公開鍵と秘密鍵を作ってherokuに公開鍵を登録します。また、gitでpushするときはもう片方の秘密鍵を使うことがが出来る設定をします。

8.3.1 キーペアの作成

オプションはテキトーに。

ssh-keygen -t rsa -b 4096

~/.ssh/herokuという名前で鍵ファイルを保存したことにします。

8.3.2. ~/.ssh/configの設定

~/.ssh/config
+ Host heroku.com
+   HostName heroku.com
+   User git
+   IdentityFile ~/.ssh/heroku

8.4. package.jsonの設定

herokuはpackage.jsonがあるかどうかでpushされたアプリケーションがnodeだと認識しているっぽいです。とりあえずnodeのバージョンを指定しておけば動きます。

package.json
{
+ "engines": {
+   "node": ">=8.2.0 <8.3.0"
+ },
}

8.5. リモートへpush

git push heroku master

これでビルドが開始されます。問題無く終わればhttps://アプリ名.herokuapp.comでアクセスできます。

9. Circle CI

下記の4つを出来るようにします。

  • テスト
  • ビルド
  • ビルドしたソースのダウンロード
  • herokuへのデプロイ

CircleCI2.0を使います。gitのリポジトリへpushしたらとにかく動くようになっています。
workflowをつかったりブランチで動作を分けたりも出来ますがここではシンプルにしてあります。
CircleCIの使い方自体は省きます。

CircleCIのWebUIからherokuとの連携が必要です。
CircleCI2.0だとyml上で設定するだけでデプロイするなんてことは出来ないのですが連携しておけば公開鍵がherokuへ登録されるので自前でキーペア作ってherokuとCircleCIの両方に設定とか面倒なことしなくてすみます。

9.1. 設定ファイル

.circleci/config.yml
version: 2
jobs:
  build:
    docker:
      # CircleCI2はdockerコンテナで動くので動作させるイメージファイルを指定します。
      # DockerHub上にあるイメージ指定します。nodeだと https://hub.docker.com/r/circleci/node/
      - image: circleci/node:8.2.1

    # コンテナ上での作業ディレクトリです。
    working_directory: ~/repo
    steps:
      # githubからチェックアウト
      - checkout

      # キャッシュの読み込み。下の方でnode_modules/以下をキャッシュする設定している。
      # キャッシュの区別にpackage.jsonじゃなくてyarn.lockファイルを使った方がいい気もする。
      - restore_cache:
          keys:
          - v1-dependencies-{{ checksum "package.json" }}
          # fallback to using the latest cache if no exact match is found
          - v1-dependencies-

      - run: yarn install

      # yarn installでインストールしたモジュールをnode_modulesごとキャッシュ。
      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package.json" }}

      # テスト
      - run: yarn test

      # ビルド
      - run: yarn build

      # 自作のスクリプトでダウンロード用にbuildディレクトリをtar.gzファイルにしている。
      - run : bash .circleci/create-artifacts.sh

      # ビルドしたファイルをダウンロードできるようにする。
      # ビルド後にArtifactsというタブができるのでそこからダウンロードできる。
      - store_artifacts:
          path: ~/repo/artifacts
          destination: artifact-file


      # herokuへの接続設定
      # CircleCI上で'HEROKU_APP_NAME'という名前でherokuのApp名を設定しておく。
      - run: bash .circleci/setup-heroku.sh

# これ書かなくてもCircleCI上の秘密鍵は全部入るっぽい?
#      - add_ssh_keys:
#          fingerprints:
#            - "ce:e9:5d:a1:3e:e4:f6:36:d0:b7:2b:4a:0d:64:91:3a"

      # masterブランチの場合だけherokuへpush
      - deploy:
          name: Deploy Master to Heroku
          command: |
            if [ "${CIRCLE_BRANCH}" == "master" ]; then
              git push heroku master
            fi


シェルスクリプトが使えるしsshでコンテナに入ることも出来るし頑張れば何でも出来そうですw

9.2. Slack

SlackとのインテグレーションはWebUIの設定画面にあるChat Notificationsから簡単にできます。

以上で一通り動きますのでプロジェクトによって色々カスタマイズしていければなと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
51
Help us understand the problem. What are the problem?