学びながらReact環境構築

# これは何？
React + TypeScriptでアプリを開発する時、最低限の環境構築方法を自分の備忘録も兼ねて記事にしたものです。

# create-react-app
まずは`create-react-app`です。
Ruby on Railsの`rails new`みたいなコマンドですね。プロジェクトを開始するときにいい感じにセットアップしてくれます。
しかもJestやReact Testing Libraryもセットアップしてくれています。素敵ですね。

```
$ mkdir <App Name> && cd <App Name>
$ yarn create react-app . --template typescript
```

# ESLint
JavaScriptのLinterであるESLintです。
TypeScriptの場合TSLintで構文チェックも可能ですが、現在は非推奨になっているのでESLintで構文チェックしましょう。

まずはESLintと各種プラグインをインストールします。

```
$ yarn add -D eslint
$ yarn add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-jest eslint-plugin-react eslint-plugin-react-hooks
$ yarn eslint --init
```

`yarn eslint --init`で質問に答えながらESLintの設定ファイル`.eslintrc.js`を作成します。
出来上がった`.eslintrc.js`に色々と追記します。

```js
module.exports = {
  env: {
    browser: true,
    es2020: true,
    'jest/globals': true,
  },
  plugins: ['react', 'react-hooks', '@typescript-eslint', 'jest'],
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:jest/recommended',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: 'module',
  },
  globals: { module: 'readonly' },
  rules: {
    'newline-before-return': 'error',
    'no-console': 'warn',
    'no-continue': 'off',
    'require-yield': 'error',

    // 中身がないタグを閉じる
    'react/self-closing-comp': [
      'error',
      {
        component: true,
        html: true,
      },
    ],

    'react/prop-types': 'off',
  },
};
```
基本的には個別のルールをあまり設定せず、recommendedな設定にします。

続けて、`.eslintignore`を作成します。

```
$ touch .eslintignore
```
`.eslintignore`は文字通り、ESLintの構文チェックから無視するファイルやディレクトリを指定するファイルです。

```
node_modules/
*.config.js
```

# Prettier
Prettierはコードの見た目をきれいに整えてくれるツールです。
ESLintと役割が似ていますが、Prettierは構文をチェックするわけではなく、スペースや改行をいい感じに整えてくれるだけです。
とはいえESLintとPrettierは見ている対象が被ることが多いので、ESLint用のプラグインでうまく共存できるようにする必要があります。
そのためのパッケージを色々インストールします。そして`.prettierrc`も作成します。

```
$ yarn add -D prettier eslint-config-prettier eslint-plugin-prettier
$ touch .prettierrc
```

`.prettierrc`はPrettierの設定ファイルです。
自分の好みに合わせて設定を記述します。

```
{
  "bracketSpacing": true,
  "printWidth": 100,
  "semi": true,
  "singleQuote": true,
  "trailingComma": "all",
  "useTabs": false
}
```
`.eslintrc.js`にPrettierとの併用設定を追加します。

```js
module.exports = {
  env: {
    browser: true,
    es2020: true,
    'jest/globals': true,
  },
  plugins: ['react', 'react-hooks', '@typescript-eslint', 'prettier', 'jest'],
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:jest/recommended',
    'plugin:prettier/recommended', // prettierの設定は一番下に
    'prettier',
    'prettier/@typescript-eslint',
    'prettier/react',
    'prettier/standard',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: 'module',
  },
  globals: { module: 'readonly' },
  rules: {
    'newline-before-return': 'error',
    'no-console': 'warn',
    'no-continue': 'off',
    'require-yield': 'error',

    // 中身がないタグを閉じる
    'react/self-closing-comp': [
      'error',
      {
        component: true,
        html: true,
      },
    ],

    'react/prop-types': 'off',

    // for prettier
    'prettier/prettier': [
      'error',
      {
        singleQuote: true,
        trailingComma: 'all',
      },
    ],
  },
};
```

最後に、`package.json`の`npm scripts`に以下のコマンドを追加します。

```json
"lint": "yarn eslint src/**/*.tsx --fix",
```

# Jest
JestはJavaScriptのためのテスト用フレームワークです。ちなみにReactと同じくFacebookが開発しています。
`package.json`にJestの設定を追加します。これはテストのカバレッジを計測する対象を指定する設定です。
最後の行はStorybookを使う場合の設定です。今回は必要ではないですがカバレッジに関係ないファイルはこんな感じで除外します。

```json
"jest": {
  "collectCoverageFrom": [
    "src/**/components/**/*.{js,jsx,ts,tsx}",
    "src/**/container/**/*.{js,jsx,ts,tsx}",
    "!<rootDir>/node_modules/",
    "!src/**/*.stories.{js,jsx,ts,tsx}"
  ]
}
```
テストカバレッジを計測するためのnpm scriptsも追加します。

```
"test:c": "react-scripts test --coverage --watchAll=false",
```

# husky & lint-staged
huskyは`git commit`や`git push`の際に発生するGitフックを`package.json`でハンドリングできる優れものです。
これでコミットする前に`eslint --fix`したいのですが、このままだと`.eslintignore`で設定したファイル以外全てを構文チェックしてしまい、非効率的です。
というわけでlint-stagedを使います。lint-stagedは、ステージングされたファイルだけに任意のスクリプトを実行できるようにするツールです。
では早速インストールします。

```
$ yarn add -D husky lint-staged
```

package.jsonに以下の設定を追記

```json
"husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "src/**/*.{js,jsx,ts,tsx}": "eslint --fix"
  }
``` 

# おまけ(VScode Settings)
これはVScodeを使っている私の好みの設定です。

```
$ mkdir .vscode && touch .vscode/settings.json
```

`.vscode/settings.json`に以下の通り設定を記述します。

```json
{
  "css.validate": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "editor.formatOnSave": true,
  "editor.tabSize": 2,
  "editor.wordWrap": "on",
  "eslint.enable": true,
  "eslint.packageManager": "yarn",
  "files.insertFinalNewline": true,
  "files.trimTrailingWhitespace": true,
  "typescript.tsdk": "node_modules/typescript/lib",
  "[markdown]": {
    "files.trimTrailingWhitespace": false
  }
}
```

## 参考
[Prettier 入門 ～ESLintとの違いを理解して併用する～](https://qiita.com/soarflat/items/06377f3b96964964a65d)