Open14

React+TypeScript+ESLint+Prettier+Docker環境構築【2022年3月版】

AsaneAsane

プロジェクトを作成する

今回はこのような構造で作成しました。

ディレクトリ構造
app/
├── app/
├── Dockerfile
└── docker-compose.yml   
AsaneAsane

Docker環境を整える

docker-compose.ymlを記述

CHOKIDAR_USEPOLLING=trueはReactでの環境構築でのホットリロードバグの回避です
今回はバックエンドやデータベースはDockerで作成しませんが、使用する場合は追加で記述すると出来ます。

docker-compose.yml
version: '3.9'
services:
  app:
    # コンテナ名を指定
    container_name: app
    # イメージを指定
    build:
      context: .
      dockerfile: Dockerfile
    # 再起動設定
    restart: always
    # ボリュームバインド
    volumes:
      - ./app:/app
    # 起動時のカレントディレクトリ
    working_dir: /app
    # 起動時に実行するコマンド
    command: node
    # コンテナを起動させ続ける設定
    tty: true
    # 環境変数を定義
    environment:
      - CHOKIDAR_USEPOLLING=true
    # 使用するポート番号
    ports:
      - 3000:3000
      - 6006:6006
    # 使用するネットワーク
    networks:
      - container-link

networks:
  container-link:

StoryBook用にポートを二つ使っていますが、必要ない場合は6006番ポートは消して大丈夫です。

Dockerfileを記述

最初の起動では一文だけで大丈夫です。

Dockerfile
FROM node:16.13.1-alpine3.14

後ほど必要部分の追加をします。
バージョンは好きなバージョンを指定してください
https://hub.docker.com/_/node

AsaneAsane

React環境を作成

自分はYarnよりもnpmの方が好きなので、--use-npmを指定していますが好きな方を選んでください。

cd app
npx create-react-app . --template typescript --use-npm

appフォルダに直接プロジェクトを作成するのでフォルダ名指定は.で大丈夫です。
これだけでReact+TypeScript環境は作れます。

ちなみに

dockerのコンテナ内でプロジェクトを作成するとバグる時やインストールが遅かったりします。
最初のプロジェクト作成はパソコンにnodeを入れてインストールする事をお勧めします。

AsaneAsane

途中経過のディレクトリ構造

app/
├── Dockerfile
├── app
│   ├── README.md
│   ├── node_modules
│   ├── package-lock.json
│   ├── package.json
│   ├── public
│   ├── src
│   └── tsconfig.json
└── docker-compose.yml
AsaneAsane

ESLintのインストール

今回は--use-npmを使用したのでnpm installの方を使用します。
--use-npmを使用しない場合はyarn addを使用。

npm install eslint --save-dev
# or
yarn add eslint --dev
AsaneAsane

ESLintの初期設定

npm init @eslint/config
# or
yarn create @eslint/config

こちらのコマンドを使用すると選択項目が表示されると思いますので、選択して行きます。

ESLintの設定選択

  • How would you like to use ESLint?
    To check syntax, find problems, and enforce code styleを選択
? How would you like to use ESLint? …
  To check syntax only
  To check syntax and find problems
❯ To check syntax, find problems, and enforce code style
  • What type of modules does your project use? …
    JavaScript modules (import/export)を選択
? What type of modules does your project use? …
❯ JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these
  • Which framework does your project use? …
    Reactを選択
? Which framework does your project use? …
❯ React
  Vue.js
  None of these
  • Does your project use TypeScript?
    Yesを選択
? Does your project use TypeScript? › No / Yes
  • Where does your code run?
    Browserを選択
? Where does your code run? …  (Press <space> to select, <a> to toggle all, <i> to invert selection)
✔ Browser
✔ Node
  • How would you like to define a style for your project? …
    Use a popular style guideを選択
? How would you like to define a style for your project? …
❯ Use a popular style guide
  Answer questions about your style
  • Which style guide do you want to follow? …
    Airbnb: https://github.com/airbnb/javascriptを選択
    これは、どれでもいいですが今後の設定が変わります。
    ちなみに一番厳しくチェックするのがAirbnbになります。
? Which style guide do you want to follow? …
❯ Airbnb: https://github.com/airbnb/javascript
  Standard: https://github.com/standard/standard
  Google: https://github.com/google/eslint-config-google
  XO: https://github.com/xojs/eslint-config-xo
  • What format do you want your config file to be in? …
    JavaScriptを選択
    これもなんでもいいです。
    設定ファイルの書き方が変わるだけ
? What format do you want your config file to be in? …
❯ JavaScript
  YAML
  JSON
  • Would you like to install them now with npm?
    Yesを選択
? Would you like to install them now with npm? › No / Yes
AsaneAsane

ESLint(Airbnb)の追加パッケージをインストール

Which style guide do you want to follow? …での選択で
Airbnb: https://github.com/airbnb/javascriptを選択した場合に必要になるパッケージをインストールします。
そのほかを選択しても何かしらの追加パッケージが必要になる可能性がありますので、公式サイトを参照してください。

Airbnbのプラグインを入れる

npm install --save-dev @typescript-eslint/eslint-plugin @typescript-eslint/parser
# or
yarn add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser

詳細設定を追加

これで細かい設定をやってくれます

npx install-peerdeps --dev eslint-config-airbnb
AsaneAsane

Prettierのインストール

Prettierのインストールはこれだけ

npm install --save-dev prettier eslint-config-prettier
# or
yarn add -D prettier eslint-config-prettier
AsaneAsane

ESLintの基本設定を追加

最小構成だとこちらになります。

.eslintrc.js
module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    'plugin:react/recommended',
    'airbnb',
+   'airbnb/hooks',
+   'plugin:@typescript-eslint/recommended',
+   'plugin:@typescript-eslint/recommended-requiring-type-checking',
+   'prettier',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 'latest',
    sourceType: 'module',
+   tsconfigRootDir: __dirname,
+   project: ['./tsconfig.json'],
  },
  plugins: ['react', '@typescript-eslint'],
+ ignorePatterns: ['.eslintrc.js'],
  rules: {},
+ settings: {
+   'import/resolver': {
+     node: {
+       paths: ['src'],
+      extensions: ['.js', '.jsx', '.ts', '.tsx'],
+     },
+   },
+ },
};

AsaneAsane

必要ファイルの追加

./app/app/にファイルを追加します

Prettierの設定ファイルの追加

.prettierrc.jsというファイルを作成

.prettierrc.js
module.exports = {
 printWidth: 120,
 singleQuote: true,
 semi: false,
}

ESLintの除外ファイルの指定

.eslintignoreというファイルを作成

.eslintignore
build/
public/
**/node_modules/
*.config.js
.*lintrc.js
/*.*
AsaneAsane

コマンドを楽にする

ESLintPrettierのコマンドを省略し、使いやすくする設定をします
package.jsonのファイルのscriptsの部分に追加します

package.json
"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
+   "lint": "eslint --ext .ts,.tsx ./src",
+   "fix": "yarn format && yarn lint:fix",
+   "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx}'",
+   "lint:fix": "eslint --fix 'src/**/*.{js,jsx,ts,tsx}'"
  },
AsaneAsane

ESLintのルールを追加

デフォルトのルールのままだと厳しすぎる為、ルールを少し優しくします。
.eslintrc.jsの中のrulesに以下の内容を追加してください。

.eslintrc.js
rules: {
    'no-use-before-define': 'off',
    '@typescript-eslint/no-use-before-define': 'off',
    'import/prefer-default-export': 'off',
    'import/extensions': [
      'error',
      {
        js: 'never',
        jsx: 'never',
        ts: 'never',
        tsx: 'never',
      },
    ],
    'react/jsx-filename-extension': [
      'error',
      {
        extensions: ['.jsx', '.tsx'],
      },
    ],
    'react/react-in-jsx-scope': 'off',
    'no-void': [
      'error',
      {
        allowAsStatement: true,
      },
    ],
  },
AsaneAsane

Airbnbの最新バージョンの悪きルール

Airbnbの最新バージョンではあまりよろしくないエラー検知があります。
エラー内容は以下

Function component is not a function declarationeslintreact/function-component-definition eslint(react/function-component-definition)

ダウングレードするかrulesに再度追加する必要があります。
追加ルールは以下になります。

'react/function-component-definition': [
    2,
    {
        namedComponents: 'arrow-function',
        unnamedComponents: 'arrow-function',
    },
],

他にも方法があるかも?

AsaneAsane

デフォルトのエラーを修正

create-react-appではデフォルトでESLintエラーになる部分があるので修正します。

App.tsx
import { VFC } from 'react'
import logo from './logo.svg'
import './App.css'

const App: VFC = () => (
  <div className="App">
    <header className="App-header">
      <img src={logo} className="App-logo" alt="logo" />
      <p>
        Edit <code>src/App.tsx</code> and save to reload.
      </p>
      <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer">
        Learn React
      </a>
    </header>
  </div>
)

export default App
App.test.tsx
- import React from 'react';
reportWebVitals.ts
import { ReportHandler } from 'web-vitals';

const reportWebVitals = (onPerfEntry?: ReportHandler): void => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    void import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      getCLS(onPerfEntry);
      getFID(onPerfEntry);
      getFCP(onPerfEntry);
      getLCP(onPerfEntry);
      getTTFB(onPerfEntry);
    });
  }
};

export default reportWebVitals;