Create React App を使わずに React & TypeScript 環境を作る(2021 年 7 月) その 3

Create React App を使わずに React & TypeScript 環境を作る(2021 年 7 月) その 3

みなさまこんにちはゴリさんです。
今日は Create React App 未使用の環境作りの続きを書いていきたいと思います。

前回までの記事はこちら

今回使用するライブラリ類のバージョン

環境は macOS Big Sur(11.2.1)です。
前提として node.js(v14.15) と npm(v7.5) が必要です。

今回使用する主要なライブラリのバージョンは以下の通りです。

  • ESlint(7.31)
  • Prettier(2.3)
  • eslint-config-prettier(8.3)

最終的には redux-toolkit、material-ui の導入まで行う予定ですが、似た様な記事がたくさんあるので私は自分の勉強のためにも step by step で少しづつ記事にしていこうかと考えています。

今日のゴール

ESlint、Prettier を導入します。

ESlint の導入

導入の前に ESlint の説明を少し、ESLint は簡単に言うと javascript の静的解析ツールです。
未使用の変数を見つけて警告してくれたり、let で宣言しているのに代入していない場合 const を使用するよう警告をしてくれたりと不具合の元となるような良くないコードを機械的に検出してくれます。
(ちなみに昔は typescript 向けの TSlint というプロダクトがありましたが、2019 年に ESlint へ統合され現在は非推奨となっています)

早速 npm で必要なパッケージを入れていきましょう。

$ npm i -D eslint eslint-webpack-plugin

ESLint 本体、webpack のプラグインです。

まずは webpack.config.js を編集し、ESLintPlugin を組み込んでください。
ファイルの最初の方でモジュールを読み込みます。1

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
// 読み込み
const ESLintPlugin = require("eslint-webpack-plugin");

...

次に HtmlWebpackPlugin の後ろに ESlint のプラグインを追加しましょう。

  ...
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "src/index.html"),
    }),
    // 追加
    new ESLintPlugin({
      extensions: ["ts", "tsx", "js"],
    }),
  ],
  ...

続けて ESlint の初期設定コマンドで設定ファイルを作成します。
コマンド投入後、以下の様に選択します。

$ npx eslint --init
✔ 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)
  CommonJS (require/exports)
  None of these

✔ Which framework does your project use?
❯ React
  Vue.js
  None of these

✔ Does your project use TypeScript?
❯ YES
  NO

✔ Where does your code run?
❯ Browser
  Node

✔ What format do you want your config file to be in?
❯ JavaScript
  YAML
  JSON

選択した内容に合わせてパッケージをインストールする様に促されますので YES を選びます。

The config that you've selected requires the following dependencies:

eslint-plugin-react@latest @typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest
✔ Would you like to install them now with npm?
❯ YES
  NO

Installing eslint-plugin-react@latest, @typescript-eslint/eslint-plugin@latest, @typescript-eslint/parser@latest

これで依存パッケージと初期設定ファイルが作成されました。

プロジェクトルートに”.eslintrc.js”というファイルが増えていると思いますので開いて、parserOptions に projectとしてtsconfig.jsonへの参照を設定し、ルートに settings を追加してreactのバージョン設定を追加します。

  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: "module",
    // 追加
    project: "./tsconfig.json", 
  },
  // 追加
  settings: {
    react: {
      version: "17",
    },
  },

package.json を開き、scripts に lint コマンドを追加しましょう。

  ...
  "scripts": {
    "tsc": "tsc",
    ...
    "start": "run-p tsc:watch webpack:start",
    // 以下の二行追加
    "lint": "eslint src",
    "lint:fix": "eslint --fix src"
  },
  "keywords": [],
  ...

lintがチェックのみのコマンド、lint:fixがチェック&修正のコマンドですね。
早速チェックを行うコマンドを叩いてみます。

$npm run lint

> example-app@1.0.0 lint
> eslint src

何も出力されませんね、違反する様に Hello.tsx の最終行のセミコロンをムダに増やしてみましょう。

      return "こんばんは!";
    }
  };

  return <h1>{buildGreetingText(new Date())}</h1>;
};

export default Hello;;

もう一度叩いてみます。

$npm run lint

> example-app@1.0.0 lint
> eslint src

/src/Hello.tsx
  19:22  error  Unnecessary semicolon  @typescript-eslint/no-extra-semi

✖ 1 problem (1 error, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.

エラーになりましたね。

webpackのビルドでもエラーになるか確認しましょう。

$ npm run build
...

ERROR in
/src/Hello.tsx
  19:22  error  Unnecessary semicolon  @typescript-eslint/no-extra-semi

✖ 1 problem (1 error, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.


webpack 5.28.0 compiled with 1 error in 6536 ms
ERROR: "webpack:build" exited with 1.

ちゃんとエラーになってますね、OK です。

では続いて fix を実行してみます。

$npm run lint:fix

> example-app@1.0.0 lint:fix
> eslint --fix src

成功です。Hello.tsx を開くと最終行のセミコロンが1つになっていると思います。

Prettier の導入

次はフォーマッターの prettier を導入しましょう。
チームで開発する際に同じフォーマットが適用されること事で差分が明確となり、差分確認や不具合の原因追求がやりやすくなります。

npm で必要なパッケージを入れていきましょう。

$ npm i -D prettier eslint-config-prettier eslint-plugin-prettier

Prettier 本体、eslint 向けの重複ルールを無効化するための設定と ESLint 実行時に prettier を実行するためのプラグインです。

“.prettierrc”という名前でプロジェクトルートに Prettier の設定ファイルを作ります。

{
    "tabWidth": 2,
    "useTabs": false,
    "semi": true
}

上から、タブはスペース2つ、タブは使わない、ステートメントの最後にセミコロンを追加という設定です。

続いて “.eslintrc.js”を開いてESLintのextends に Prettier を組み込みます。

module.exports = {
  ...
  extends: [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended",
    // 以下の二行を追加
    "plugin:prettier/recommended",
    "prettier",
  ],
  ...
};

では lint コマンドを叩いてみます。

$npm run lint

> example-app@1.0.0 lint
> eslint src

何も出力されませんね、例によって Hello.tsx を開き今度は関数部分の改行を取ってみましょう

import * as React from "react";

const Hello: React.FC = () => {
  const buildGreetingText: (date: Date) => string = (date) => {
    // 0 ~ 23 の範囲なので+1
    const hours = date.getHours() + 1;    if (5 < hours && hours < 11) {      return "おはようございます!";    } else if (11 < hours && hours < 16) {      return "こんにちは!";    } else {      return "こんばんは!";    }
  };

  return <h1>{buildGreetingText(new Date())}</h1>;;
};

export default Hello;

もう一度叩いてみます。

$npm run lint

> example-app@1.0.0 lint
> eslint src
npm run lint

> example-app@1.0.0 lint
> eslint src

/src/Hello.tsx
  6:39  error  Replace `····if·(5·<·hours·&&·hours·<·11)·{······return·"おはようございます!";····}·else·if·(11·<·hours·&&·hours·<·16)·{······return·"こんにちは!";····}·else·{······return·"こんばんは!";` with `⏎····if·(5·<·hours·&&·hours·<·11)·{⏎······return·"おはようございます!";⏎····}·else·if·(11·<·hours·&&·hours·<·16)·{⏎······return·"こんにちは!";⏎····}·else·{⏎······return·"こんばんは!";⏎`  prettier/prettier
  9:50  error  Delete `;`                                                                                                                                                                                                                                                                                                                                             prettier/prettier

✖ 2 problems (2 errors, 0 warnings)
  2 errors and 0 warnings potentially fixable with the `--fix` option.

今度はエラーになりましたね、OKです。
では続いて fix を実行してみます。

$npm run lint:fix

> example-app@1.0.0 lint:fix
> eslint --fix src

成功です。Hello.tsx を開き直すと関数の中身が整形されていると思います。

vscode に拡張機能をインストール

コマンドを叩けば静的コード解析とフォーマットが行える様になりました。
ただ、このままだと毎回コマンドを叩くことになるのでちょっと面倒くさいですよね?

デファクトの感が出てきた人気のエディタ VSCode の拡張機能を導入し、ファイルを保存したタイミングでコード解析とフォーマットを行う様にしてみましょう。

最初に ESLint の拡張機能をインストールしてみましょう。
拡張機能のマーケットプレイスで「dbaeumer.vscode-eslint」を検索し、以下の拡張機能をインストールします。

続けて「esbenp.prettier-vscode」と検索し、以下の拡張機能をインストールします。

拡張機能の設定を行います。
VSCode のコマンドパレットを開き、「settings json」と入力して設定を json で開いてください。

設定に以下を追加します。

  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
      "source.fixAll.eslint": true
  },

これで拡張機能の設定は完了です。
Hello.tsx を開いて以下の様に適当にフォーマット違反する様に編集してから保存してみてください。

import * as React from "react";

const Hello: React.FC = () => {
  const buildGreetingText: (date: Date) => string = (date) => {
    // 0 ~ 23 の範囲なので+1
    const hours = date.getHours() + 1;
    if (5 < hours && hours < 11) {
      return "おはようございます!";    } else if (11 < hours && hours < 16) {
      return "こんにちは!";    } else {      return "こんばんは!";
    }
  };

  return <h1>{buildGreetingText(new Date())}</h1>;;
};

export default Hello;

自動的に lint とフォーマットが適用されると思います。

ESLintとPrettierはそれぞれ細かく設定が行えます。
推奨ルールを基本にプロジェクトに合わせて調整してみましょう。
ESLint: https://eslint.org/docs/rules/
Prettier: https://prettier.io/docs/en/options.html

今回はここまでとします、お疲れ様でした!

一覧へ戻る

最新記事