概要
react アプリを TypeScipt で開発する際の定番の設定をまとめておく。
- TypeScript で記述
- eslint で構文チェック(クォーテーションマークの統一、import 文のソート)
- jest でユニットテスト
- commitlint で commit log が semantic versioning に準拠しているかチェックし、エラーが出たときには commit 中止
- commit 前に eslint, jest を自動実行し、エラーが出たときには commit 中止
- Sourcetree からも上記のフックが正しく実行されるように細工
この環境設定を行なった git repo はこちら。https://gitlab.com/ken.miyasita/react-app-on-gitlab-pages/-/tree/main
全体像
react アプリケーションの雛形を準備
参照: Create React App
$ node --version
v15.14.0
$ npx create-react-app react-app-on-gitlab-pages --template typescript
$ cd react-app-on-gitlab-pages
$ yarn start
eslint
参照
* Getting Started with ESLint - ESLint - Pluggable JavaScript linter
* Getting Started - Linting your TypeScript Codebase
* eslint-plugin-simple-import-sort
lint ルールをいくつか設定しておく。
- 文字列は、全てシングルクオートマークにする
- import 文は、いくつかのカテゴリに分け、それぞれのカテゴリー内は import 対象のパス名でソートする
$ yarn add eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-simple-import-sort --dev
{
"env": {
"browser": true,
"es6": true,
"node": true
},
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint",
"simple-import-sort"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"quotes": [
"error",
"single"
],
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error"
}
}
"scripts": {
"lint": "eslint . --ext .ts,.tsx"
},
jest
参照:Running Tests | Create React App
Create react app が自動生成する package.json の script 定義は以下のようになっており、
環境変数 CI
が設定されているか否かで test
の挙動が変化するようになっている。
"scripts": {
"test": "react-scripts test",
},
-
CI
が定義されていないときには watch モードで動作。ソースコードが変更されるたびに、変更されたソースコードに関連するテストのみ実行される。 -
CI
が定義されているときには、全テストを実行。Predefined variables reference - GitLab によると GitLab CI/CD 環境でもCI=true
が設定されている。 - もしくは
yarn test --watchAll=false
として起動すれば、全テストを実行。この機能は後で commit 時に test を実行するために利用する。
commitlint を husky を使って起動する
参照:
* commitlint - Lint commit messages
* commitlint - Lint commit messages > Guide: Local setup
commit log を semantic versioning に準拠した形に維持するために commitlint を導入する。
$ yarn add @commitlint/{cli,config-conventional} --dev
$ echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
$ yarn add husky --dev
$ npm set-script prepare "husky install"
$ yarn prepare
$ yarn husky add .husky/commit-msg 'yarn commitlint --edit $1'
semantic versioning に適合しない commit log を指定して commit しようとしてもエラーとなることが確認できる。
$ git commit -m'foo:aaa'
yarn run v1.22.11
$ /Users/kmiyashita/gitlab/react-app-on-gitlab-pages/node_modules/.bin/commitlint --edit .git/COMMIT_EDITMSG
⧗ input: foo:aaa
✖ subject may not be empty [subject-empty]
✖ type may not be empty [type-empty]
✖ found 2 problems, 0 warnings
ⓘ Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
husky - commit-msg hook exited with code 1 (error)
commit 時に lint, jest を起動する
せっかく husky を導入したので、commit 時には lint, jest が必ずパスすることを確認することにする。
$ yarn husky add .husky/pre-commit 'yarn lint && yarn test --watchAll=false'
確かに、lint と jest が実行されることを確認できた。
$ git commit -m 'feat: run lint and jest at every commit'
yarn run v1.22.11
$ eslint . --ext .ts,.tsx
✨ Done in 0.58s.
yarn run v1.22.11
$ react-scripts test --watchAll=false
PASS src/App.test.tsx
✓ renders learn react link (14 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.006 s
Ran all test suites.
✨ Done in 1.56s.
yarn run v1.22.11
$ /Users/kmiyashita/gitlab/react-app-on-gitlab-pages/node_modules/.bin/commitlint --edit .git/COMMIT_EDITMSG
✨ Done in 0.21s.
[main 0a560aa] feat: run lint and jest at every commit
2 files changed, 5 insertions(+), 1 deletion(-)
create mode 100755 .husky/pre-commit
ただ、開発中の feature branch では lint, jest が一時的にパスしない状態でも commit をして状態保存をしながら開発し、最後に interactive rebase で commit log を整理してから main branch にマージすることも多々あると予想される。それを考えると常に lint, jest がパスしないと commit できないというルールは厳しすぎるかもしれないので、結局以下のように main branch でのみこのルールを発動するようにした。
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
branch="$(git rev-parse --abbrev-ref HEAD)"
if [ "$branch" = "main" ]; then
yarn lint && yarn test --watchAll=false
fi
Sourcetree から commit したときにも commit hook を動作させる
参考:
* Launching a macOS application with a custom path
* Can I change the application icon of an Automator script?
ここまでで Terminal から git 操作した時の挙動はうまく設定できたが、Sourcetree から commit をしようとするとうまく動作しない。以下のように yarn が見つからないというエラーが出る。
これは、Sourcetree のように Dock / Finder から起動されたアプリにとっては PATH 変数がデフォルト設定のままになっており、自分で yarn
等をインストールしたフォルダーを .zshrc
等で PATH 変数に追加していてもそれが反映されないことが原因である。
この問題を回避するためには、Automator を利用して下図のように .zshrc
等を読み込んでから Sourcetree を起動すれば良い。ある意味、shell script を Dock / Finder に置いていると考えられる。
このようにして PATH 設定をした状態の Sourcetree を用いると、下図のように commit 時に lint, jest が起動される。