React@TS初期設定（create-react-app, eslint, prettier, stylelint）

Reactでアプリ開発初期設定のメモです。

　
りあクト！3.1版を参考にしています。

https://oukayuka.booth.pm/

#環境
+ Ubuntu 20.04.3 LTS
+ VSCode
+ NodeJS v16.13.0

#インストール
##1. React本体（create-react-app利用）

```bash:Terminal
$ npx create-react-app@5.0.0 (app-name) --template=typescript
```

Installing **react**, **react-dom**, and **react-scripts** with *cra-template-typescript*...
された。

<details>
<summary>@5.0.0を指定した流れ</summary>
<div>

```bash:Terminal
$ npx create-react-app (app-name) --template=typescript
```


```
Need to install the following packages:
  create-react-app
Ok to proceed? (y) 
```

npxはインストールされないのでは…？why?
とりあえずproceedしてみる

```
You are running `create-react-app` 4.0.3, which is behind the latest release (5.0.0).

We no longer support global installation of Create React App.

Please remove any global installs with one of the following commands:
- npm uninstall -g create-react-app
- yarn global remove create-react-app

The latest instructions for creating a new app can be found here:
https://create-react-app.dev/docs/getting-started/
```

Globalインストールしてないんだけどなぁ、、
一応確認

```
$ which creact-react-app
```

やはり該当なし。

とりあえず5.0.0使えということなので冒頭のように@5.0.0指定したら普通に通った。
（2021-12-18）
この記事書いてる直前にcreate-react-appが5.0.0が出たぽい。npxがまだ対応してなかったのかな。
https://qiita.com/daishi/items/d0a063b8902fc988adb2
</div>
</details>

```bash:Terminal
$ cd (app-name)
$ yarn start
```

無事にReactロゴがクルクル回ってくれたのでクリア。

 
##2. ESLint



```bash:Terminal
$ yarn list eslint
yarn list eslint
yarn list v1.22.17
error No lockfile in this directory. Run `yarn install` to generate one.
info Visit https://yarnpkg.com/en/docs/cli/list for documentation about this command.
```
lockfileがないからyarn installしろと怒られたのでやった

```bash:Terminal
$ yarn install
```
yarn.lockできたので、再び

```bash:Terminal
$ yarn list eslint
yarn list v1.22.17
warning Filtering by arguments is deprecated. Please use the pattern option instead.
└─ eslint@8.5.0
```
eslint@8.5.0が入ってる模様

次に、`$ yarn upgrade interactive`でpackage.jsonの指定内でパッケージをアップデートする
（`--latest`は最新の安定バージョンに一括アップデートするオプション）

```bash:Terminal
$ yarn upgrade-interactive --latest
yarn upgrade-interactive v1.22.17
info Color legend : 
 "<red>"    : Major Update backward-incompatible updates 
 "<yellow>" : Minor Update backward-compatible features 
 "<green>"  : Patch Update backward-compatible bug fixes
? Choose which packages to update. (Press <space> to select, <a> to toggle all, <i> to invert selection)
 dependencies
   name         range   from         to      url
❯◯ @types/node  latest  16.11.14  ❯  17.0.0  https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node
```

後方互換性のない（red）`@types/node`だけだったので一旦`Ctrl + C`でスルー

次はtypescriptを最新版にする

```bash:Terminal
$ yarn upgrade typescript@latest
~~
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ typescript@4.5.4
info All dependencies
└─ typescript@4.5.4
```
typescript@4.5.4になった

次は`$ yarn eslint --init`で.eslintrcをつくる

```bash:Terminal
$ yarn eslint --init
yarn run v1.22.17
~~
✔ How would you like to use ESLint? · style
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser
✔ How would you like to define a style for your project? · guide
✔ Which style guide do you want to follow? · airbnb
✔ What format do you want your config file to be in? · JavaScript
Checking peerDependencies of eslint-config-airbnb@latest
Local ESLint installation not found.
The config that you've selected requires the following dependencies:

eslint-plugin-react@^7.27.1 @typescript-eslint/eslint-plugin@latest eslint-config-airbnb@latest eslint@^7.32.0 || ^8.2.0 eslint-plugin-import@^2.25.3 eslint-plugin-jsx-a11y@^6.5.1 eslint-plugin-react-hooks@^4.3.0 @typescript-eslint/parser@latest
✔ Would you like to install them now with npm? · No / Yes

Oops! Something went wrong! :(

ESLint: 8.5.0

ESLint couldn't find the config "airbnb" to extend from. Please check that the name of the config is correct.

The config "airbnb" was referenced from the config file in "".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.

error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
```
npm使わずyarn経由でインストールするために最後の`✔ Would you like to install them now with npm?`をNoにするとエラーになるけど`.eslintrc.js`は作られる

npmでインストールしなかったパッケージ群をyarnでインストールする

```bash:Terminal
$ yarn add -D eslint-plugin-react@^7.27.1 @typescript-eslint/eslint-plugin@latest eslint-config-airbnb@latest eslint eslint-plugin-import@^2.25.3 eslint-plugin-jsx-a11y@^6.5.1 eslint-plugin-react-hooks@^4.3.0 @typescript-eslint/parser@latest
~~
info Direct dependencies
├─ @typescript-eslint/eslint-plugin@5.7.0
├─ @typescript-eslint/parser@5.7.0
└─ eslint-config-airbnb@19.0.2
info All dependencies
├─ @typescript-eslint/eslint-plugin@5.7.0
├─ @typescript-eslint/parser@5.7.0
├─ eslint-config-airbnb-base@15.0.0
└─ eslint-config-airbnb@19.0.2
```

`warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.`に従ってpackage-lock.jsonを削除した

次は@typesを自動で管理してくれる`typesync`する

https://qiita.com/yamadashy/items/225f287a25cd3f6ec151

```bash:Terminal
$ typesync
»  TypeSync v0.8.0
✔  2 new typings added.

📦 todo-list — package.json (2 new typings added, 0 unused typings removed)
├─ + @types/testing-library__jest-dom
└─ + @types/testing-library__user-event

✨  Go ahead and run npm install or yarn to install the packages that were added.
```
指示に従って

```bash:Terminal
$ yarn
```
次に.eslintrc.jsに設定を記述していく（記述しないとpluginsは有効化されない）

```javascript:.eslintrc.js
//プラグインルールの共有設定　＊設定順関係ある
  extends: [
    'plugin:react/recommended',
    'airbnb',
    'airbnb/hooks',
    'plugin:import/errors',
    'plugin:import/warnings',
    'plugin:import/typescript',
    'plugin:@typescript-eslint/recommended',
    'plugin:@typescript-eslint/recommended-requiring-type-checking',
    'prettier', // 先にprettierもここで設定しておく（prettier入れるまではエラー吐くから一時コメントアウトしたほうがいいかも）
  ],
//パーサの設定
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 13, //りあクト本では12になってるけどそのまま13使う
    project: "./tsconfig.eslint.json", //tsconfig.jsonをそのまま読ませるとnpmパッケージまでパースしちゃうのでmode_modulesをexcludeするために経由させる設定ファイル。あとで作る。
    sourceType: "module",
    tsconfigRootDir: __dirname,
  },
//プラグイン読み込み
  plugins: [
    '@typescript-eslint',
    'import',
    'jsx-a11y',
    'prefer-arrow',
    'react',
    'react-hooks',
  ],
  root: true, //ESLintが親ディレクトリの設定ファイルを読みに行かないようにする（必須ではないかも）
//extendsで設定した共有設定の値を上書きする
//（りあクトで必須とされている項目プラスアルファのみとりあえず記載。必要なら後で足す）
  rules: {
    "import/extensions": [
      "error",
      "ignorePackages",
      {
        js: "never",
        jsx: "never",
        ts: "never",
        tsx: "never",
      },
    ],
    "prefer-arrow/prefer-arrow-functions": [
      "error",
      {
        disallowPrototype: true,
        singleReturnOnly: false,
        classPropertiesAllowed: false,
      },
    ],
    "react/jsx-filename-extension": [
      "error",
      {
        extensions: [".jsx", ".tsx"],
      },
    ],
    "react/react-in-jsx-scope": "off",
  },
//任意のglobパターンにマッチするファイルのみルールを上書き
  overrides: [
    {
      files: ["*.tsx"],
      rules: {
        "react/prop-types": "off",
      },
    },
  ],
//任意の実行ルールに適用される追加の共有設定
  settings: {
    "import/resolver": {
      node: {
        paths: ["src"],
      },
    },
  },
```
とりあえず最低限のルールのみ設定。必要に応じて設定を見直す。

https://eslint.org/docs/rules/


`tsconfig.eslint.json`を作る。
`tsconfig.json`を修正。
`.eslintignore`を作る。

```json:tsconfig.eslint.json
{
  "extends": "./tsconfig.json",
  "include": [
    "src/**/*.js",
    "src/**/*.jsx",
    "src/**/*.ts",
    "src/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}
```

```diff_json:tsconfig.json
{
  "compilerOptions": {
+    "baseUrl": "src",
+    "downlevelIteration": true
  },
}
```

```ignore:.eslintignore
build/
public/
**/coverage/
**/node_modules/
**/*.min.js
*.config.js
.*lintrc.js
```
VSCodeでコーディング中にESLintが走るように設定（拡張機能入れておく：
dbaeumer.vscode-eslint）

```diff_json:settings.json(VSCode)
+    "editor.codeActionsOnSave": {
+        "source.fixAll.eslint": true,
+        "source.fixAll.stylelint": true
+    },
+    "editor.formatOnSave": false,
+    "eslint.packageManager": "yarn",
+    "typescript.enablePromptUseWorkspaceTsdk": true,
```
りあクトではこの後、`./src/App.tsx`を開いて`explicit-module-boundary-types`ルールが適用されていることを確認して、エラーが出ないようにコードを書き換えているのだけど、どうもこのルールがデフォルトで有効でなくなったぽい？

https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin

このルールいらなくね？offしたわってツイートも見たので必要ないのかも。
あとでoffにするかもだけど、流れ追うために一旦有効化

```diff_javascript:.eslintrc.js
  overrides: [
    {
      files: ["*.tsx"],
      rules: {
        "react/prop-types": "off",
+       "@typescript-eslint/explicit-module-boundary-types": ["error"],
      },
    },
  ],
```
無事エラー吐くようになった。
のでりあクトに従ってコード修正。
今度は`function-component-definition`で怒られたので、アロー関数のみ許可するように追記。

```diff_javascript:.eslintrc.js
  rules: {
~~
+    "react/function-component-definition": [
+      "warn",
+      {
+        namedComponents: "arrow-function",
+        unnamedComponents: "arrow-function",
+      },
    ],
  },
```
シングルクォートにしろとか吐いてるけど一旦無視。
`package.json`のscripts設定はprettierとstylelint入れた後まとめてやる。

```diff_javascript:.eslintrc.js
  rules: {
~~
+    "react/function-component-definition": [
+      "warn",
+      {
+        namedComponents: "arrow-function",
+        unnamedComponents: "arrow-function",
+      },
    ],
  },
```


##3. Prettier

```bash:Terminal
$ yarn add -D prettier eslint-config-prettier
```
`.eslintrc.js`には記述済み（コメントアウトしてたら解除）
`.prettierrc`を作成

```.prettierrc:.prettierrc
{
  "singleQuote": true,
  "trailingComma": "all",
  "endOfLine": "auto"
}
```
ESLintルールとの衝突確認

```bash:Terminal
$ npx eslint-config-prettier 'src/**/*.{js,jsx,ts,tsx}'
No rules that are unnecessary or conflict with Prettier were found.
```
衝突はありませんでしたー。
VSCodeの設定に追記。

```diff_json:settings.json(VSCode)
+    "editor.defaultFormatter": "esbenp.prettier-vscode",
+    "[graphql]": {
+        "editor.formatOnSave": true
+    },
+    "[javascript]": {
+        "editor.formatOnSave": true
+    },
+    "[javascriptreact]": {
+        "editor.formatOnSave": true
+    },
+    "[json]": {
+        "editor.formatOnSave": true
+    },
+    "[typescript]": {
+        "editor.formatOnSave": true
+    },
+    "[typescriptreact]": {
+        "editor.formatOnSave": true
+    },
```
`./src/index.tsx`を開いてそのまま`Ctrl + S`したら`,`ついたのでちゃんと効いてそう。


##4. stylelint

```bash:Terminal
$ yarn add -D stylelint stylelint-config-standard stylelint-order stylelint-config-recess-order
$ yarn
```
設定ファイル作成

```javascript:.stylelintrc.js
module.exports = {
  extends: [
    'stylelint-config-standard',
    'stylelint-config-recess-order',
  ],
  plugins: [
    'stylelint-order',
  ],
  ignoreFiles: [
    '**/node_modules/**',
  ],
  rules: {
    'string-quotes': 'single',
  },
};
```
VSCodeの設定に追記。

```diff_json:settings.json(VSCode)
+    "css.validate": false,
+    "less.validate": false,
+    "scss.validate": false,
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true,
+        "source.fixAll.stylelint": true
    },
```
`./src/index.css`を開いて`Ctrl + S`したら無事整形された。

`package.json`のnpm scriptsに追記。

```json:package.json
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "fix": "npm run -s format && npm run -s lint:fix",
    "format": "prettier --write --loglevel=warn '{public,src}/**/*.{js,jsx,ts,tsx,html,gql,graphql,json}'",
    "lint": "npm run -s lint:style; npm run -s lint:es",
    "lint:fix": "npm run -s lint:style:fix && npm run -s lint:es:fix",
    "lint:es": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
    "lint:es:fix": "eslint --fix 'src/**/*.{js,jsx,ts,tsx}'",
    "lint:conflict": "eslint-config-prettier 'src/**/*.{js,jsx,ts,tsx}'",
    "lint:style": "stylelint 'src/**/*.{css,less,sass,scss}'",
    "lint:style:fix": "stylelint --fix 'src/**/*.{css,less,sass,scss}'",
    "preinstall": "typesync || :"
  },
```

##追加
prefer-arrowをyarn add

```bash:Terminal
$ yarn add -D eslint-plugin-prefer-arrow
```
`.eslintrc.js`に追記

```diff_javascript:.eslintrc.js
  plugins: [
    '@typescript-eslint',
    'import',
    'jsx-a11y',
+    "prefer-arrow",
    'react',
    'react-hooks',
  ],
  root: true,
  rules: {
    'import/extensions': [
      'error',
      'ignorePackages',
      {
        js: 'never',
        jsx: 'never',
        ts: 'never',
        tsx: 'never',
      },
    ],
+    "prefer-arrow/prefer-arrow-functions": [
+      "error",
+      {
+        disallowPrototype: true,
+        singleReturnOnly: false,
+        classPropertiesAllowed: false,
+      },
+    ],
     ...
  }
```

##確認

```bash:Terminal
$ yarn fix
yarn run v1.22.17
($ npm run -s format && npm run -s lint:fix)

src/App.css
  1:1   ✖  Expected class selector to be kebab-case  selector-class-pattern
  5:1   ✖  Expected class selector to be kebab-case  selector-class-pattern
 11:3   ✖  Expected class selector to be kebab-case  selector-class-pattern
 16:1   ✖  Expected class selector to be kebab-case  selector-class-pattern
 27:1   ✖  Expected class selector to be kebab-case  selector-class-pattern
 31:12  ✖  Expected keyframe name to be kebab-case   keyframes-name-pattern

src/index.css
  7:6  ✖  Unexpected quotes around "Roboto"     font-family-name-quotes
  8:6  ✖  Unexpected quotes around "Oxygen"     font-family-name-quotes
  9:6  ✖  Unexpected quotes around "Ubuntu"     font-family-name-quotes
 10:6  ✖  Unexpected quotes around "Cantarell"  font-family-name-quotes

error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
```
想定されるエラーが出ない