1. 記事一覧 >
  2. ブログ記事
category logo

React TypeScript ESLint Prettier VSCode のプロジェクト作成

(更新) (公開)

はじめに

React TypeScript ESLint Prettier VSCode(Visual Studio Code) の組み合わせで、プロジェクトを作成し、リンター、コードフォーマッター環境を構築しました。
何番煎じだよっ!とは思いますが、create-react-app のソースコードを基準に調整していくやり方で、いきなり結論を出さず、一個一個確認しながら進めて行きます。(急ぐ場合、手順まとめ に飛んでください。)


【検証環境】

Windows 10 Pro x64

 Visual Studio Code 1.69.0

Raspberry Pi Desktop OS(Linux raspberry 4.19.0-13-amd64)

 node 14.16.0

 npm 6.14.11

 create-react-app 5.0.1

 eslint 8.19.0

 prettier 2.7.1


Node インストール

Rapsberry pi OS Desktop に Node をインストールします。


Node が既にインストールされている場合は、必要ありません。Rapsberry pi OS Desktop ではない場合、別の手順になると思います。また、必ずしもこの手順である必要はありません。
本題ではないですし、別記事 VS Code で Raspberry Pi Desktop へ SSH 接続しようとしたらエラーになった に説明がありますので、詳しい説明は、省略します。

# apt update -y
# apt install -y gcc-multilib
# curl -fsSL https://deb.nodesource.com/setup_14.x | bash -
# apt update -y
# apt install -y nodejs
# node -v
v10.24.0

# apt install -y npm
# npm i -g n yarn
# n install 14.16.0
# node -v
v10.24.0

# PATH="$PATH"
# node -v
v14.16.0

# npm -v
6.14.11

VSCode SSH 接続

VSCode SSH 接続環境をセットアップします。


別記事 VS Code で Raspberry Pi Desktop へ SSH 接続しようとしたらエラーになった に説明がありますので、詳しい説明は、省略します。


VSCode で Node をインストールしたサーバーに接続できて、VSCode には、Remote Development 拡張機能のみインストール済みとします。

VSCode SSH 接続環境 設定済み


React TypeScript プロジェクト作成

create-react-app を使って、TypeScript 版 React プロジェクトを作成します。

$ npx create-react-app sample-project --template typescript
$ cd sample-project
$ npm start
Compiled successfully!

You can now view sample-project in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://192.168.11.6:3000

Note that the development build is not optimized.
To create a production build, use npm run build.

webpack compiled successfully

http://192.168.11.6:3000 に接続してみます。

http://192.168.11.6:3000 に接続


OK!


ESLint 対応

ESLint に対応します。

$ npx eslint --init

各質問を以下のように回答します。


How would you like to use ESLint?
To check syntax, find problems, and enforce code style
What type of modules does your project use?
JavaScript modules (import/export)
Which framework does your project use?
React
Does your project use TypeScript?
Yes
Where does your code run?
Browser
How would you like to define a style for your project?
Use a popular style guide
Which style guide do you want to follow?
Airbnb: https://github.com/airbnb/javascript
What format do you want your config file to be in?
JavaScript
Would you like to install them now?
Yes
Which package manager do you want to use?
npm


早速、ESLint を実行してみます。

$ npx eslint src --ext .tsx --ext .ts

/home/pi/sample-project/src/App.test.tsx
  3:17  error  Unable to resolve path to module './App'        import/no-unresolved
  3:17  error  Missing file extension for "./App"              import/extensions
  5:1   error  'test' is not defined                           no-undef
  6:10  error  JSX not allowed in files with extension '.tsx'  react/jsx-filename-extension
  8:3   error  'expect' is not defined                         no-undef

/home/pi/sample-project/src/App.tsx
   7:5   error  JSX not allowed in files with extension '.tsx'               react/jsx-filename-extension
  11:16  error  `code` must be placed on a new line                          react/jsx-one-expression-per-line
  11:40  error  ` and save to reload.        ` must be placed on a new line  react/jsx-one-expression-per-line

/home/pi/sample-project/src/index.tsx
   4:17  error  Unable to resolve path to module './App'              import/no-unresolved
   4:17  error  Missing file extension for "./App"                    import/extensions
   5:29  error  Unable to resolve path to module './reportWebVitals'  import/no-unresolved
   5:29  error  Missing file extension for "./reportWebVitals"        import/extensions
   8:49  error  Missing trailing comma                                comma-dangle
  11:3   error  JSX not allowed in files with extension '.tsx'        react/jsx-filename-extension
  13:22  error  Missing trailing comma                                comma-dangle

/home/pi/sample-project/src/reportWebVitals.ts
  5:32  error  Expected a line break after this opening brace   object-curly-newline
  5:74  error  Expected a line break before this closing brace  object-curly-newline

? 17 problems (17 errors, 0 warnings)

create-react-app で作成したソースコードでエラーが出力されます。


ソースコードを書き換えずに、これを解消していきます。


まず、何でこんなにエラーが出るのかと言うと、ESLint の設定ファイル .eslintrc.js の extends に airbnb の拡張設定(Airbnb社の考えを反映したルール設定)があるのですが、.ts, .tsx に対応していなくて、これではまだ設定が足りていないからです。

.eslintrc.js初期設定
  extends: [
    'plugin:react/recommended',
    'airbnb',
  ],

airbnb の TypeScript 拡張設定 を適用します。

$ npm install --save-dev eslint-config-airbnb-typescript

'airbnb-typescript', を追加します。

.eslintrc.js
  extends: [
    'plugin:react/recommended',
    'airbnb',
    'airbnb-typescript',
  ],

airbnb-typescript 追加


再び、ESLint を実行します。

$ npx eslint src --ext .tsx --ext .ts
Oops! Something went wrong! :(

ESLint: 8.19.0

Error: Error while loading rule '@typescript-eslint/dot-notation': You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.
Occurred while linting /home/pi/sample-project/src/App.test.tsx
    at getParserServices (/home/pi/sample-project/node_modules/@typescript-eslint/utils/dist/eslint-utils/getParserServices.js:23:15)
    at create (/home/pi/sample-project/node_modules/@typescript-eslint/eslint-plugin/dist/rules/dot-notation.js:85:81)
    at Object.create (/home/pi/sample-project/node_modules/@typescript-eslint/utils/dist/eslint-utils/RuleCreator.js:42:20)
    at createRuleListeners (/home/pi/sample-project/node_modules/eslint/lib/linter/linter.js:922:21)
    at /home/pi/sample-project/node_modules/eslint/lib/linter/linter.js:1104:110
    at Array.forEach (<anonymous>)
    at runRules (/home/pi/sample-project/node_modules/eslint/lib/linter/linter.js:1041:34)
    at Linter._verifyWithoutProcessors (/home/pi/sample-project/node_modules/eslint/lib/linter/linter.js:1393:31)
    at Linter._verifyWithConfigArray (/home/pi/sample-project/node_modules/eslint/lib/linter/linter.js:1733:21)
    at Linter.verify (/home/pi/sample-project/node_modules/eslint/lib/linter/linter.js:1475:65)

ESLint が実行できなくなりました。


TypeScript コンパイラが使用されるようになったため、ESLint に tsconfig.json ファイルの位置を教えてあげる必要があります。
project: './tsconfig.json',
を追加します。

.eslintrc.js
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 'latest',
    sourceType: 'module',
    project: './tsconfig.json',
  },

parserOptions project tsconfig.json 追加


ESLint を実行します。

$ npx eslint src --ext .tsx --ext .ts

/home/pi/sample-project/src/App.tsx
  11:16  error  `code` must be placed on a new line                          react/jsx-one-expression-per-line
  11:40  error  ` and save to reload.        ` must be placed on a new line  react/jsx-one-expression-per-line

/home/pi/sample-project/src/index.tsx
   8:49  error  Missing trailing comma  @typescript-eslint/comma-dangle
  13:22  error  Missing trailing comma  @typescript-eslint/comma-dangle

/home/pi/sample-project/src/reportWebVitals.ts
  5:32  error  Expected a line break after this opening brace   object-curly-newline
  5:74  error  Expected a line break before this closing brace  object-curly-newline

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

まだエラーが残っていますが、ここで一旦消えたエラーについて、整理します。

消えたエラー
/home/pi/sample-project/src/App.test.tsx
  3:17  error  Unable to resolve path to module './App'        import/no-unresolved
  3:17  error  Missing file extension for "./App"              import/extensions
  5:1   error  'test' is not defined                           no-undef
  6:10  error  JSX not allowed in files with extension '.tsx'  react/jsx-filename-extension
  8:3   error  'expect' is not defined                         no-undef

/home/pi/sample-project/src/App.tsx
   7:5   error  JSX not allowed in files with extension '.tsx'               react/jsx-filename-extension

/home/pi/sample-project/src/index.tsx
   4:17  error  Unable to resolve path to module './App'              import/no-unresolved
   4:17  error  Missing file extension for "./App"                    import/extensions
   5:29  error  Unable to resolve path to module './reportWebVitals'  import/no-unresolved
   5:29  error  Missing file extension for "./reportWebVitals"        import/extensions

が消えています。


$ npx eslint --print-config src/index.tsx で見ると、それぞれ、以下のように設定されたから解消されたようです。

import/no-unresolved
  "settings": {
    "import/resolver": {
      "node": {
        "extensions": [
          ".mjs",
          ".js",
          ".jsx",
          ".json",
          ".ts",
          ".tsx",
          ".d.ts"
        ]
      }
    },
  "rules": {
    "import/no-unresolved": [
      "off",
      {
        "commonjs": true,
        "caseSensitive": true,
        "caseSensitiveStrict": false
      }
    ],
import/extensions
  "settings": {
    "import/extensions": [
      ".js",
      ".mjs",
      ".jsx",
      ".ts",
      ".tsx",
      ".d.ts"
    ],
  "rules": {
    "import/extensions": [
      "error",
      "ignorePackages",
      {
        "js": "never",
        "mjs": "never",
        "jsx": "never",
        "ts": "never",
        "tsx": "never"
      }
    ],
no-undef
  "rules": {
    "no-undef": [
      "off"
    ],
react/jsx-filename-extension
  "rules": {
    "react/jsx-filename-extension": [
      "error",
      {
        "extensions": [
          ".jsx",
          ".tsx"
        ]
      }
    ],

当然、今回確認しているエラー以外にも対応されていますが、省略します。


react/jsx-one-expression-per-line
@typescript-eslint/comma-dangle
object-curly-newline
3種類のエラーがまだ残っていますが、prettier のインストールに進みます。(最終的には解消します。)


Prettier インストール

VSCode の拡張機能である ESLint と Prettier をインストールします。

Prettier インストール


ESLint インストール


設定 → リモート [SSH: 192.168.11.6] → 設定 (JSON) を開く

設定 (JSON) を開く

で、settings.json を以下のように設定します。

settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "prettier.singleQuote": true
}

"editor.defaultFormatter": "esbenp.prettier-vscode", : フォーマッタを Prettier にします。
"editor.formatOnSave": true, : 保存したときにフォーマットします。
"prettier.singleQuote": true : フォーマット時、ダブルクォートをシングルクォートに変更します。(変更可能な場合)

"prettier.singleQuote": true に関しては、create-react-app で生成したソースコードがシングルクォートを使っているため、設定します。必須ではありません。

自動フォーマットされるか、保存して確認してみます。


自動フォーマットされるか、保存して確認


OK!


ここで、例の ESLint のエラーを仮にソースコードを書き換えて修正しようとしても、Prettier が元のエラーの形に戻してしまい、解消できません。


Prettier:正しい!
ESLint:間違っている!
とお互いの主張がかみ合わず、喧嘩してしまっている状況です。

お互いの主張がかみ合わず、喧嘩してしまっている状況


ESLint(再び)

拡張設定 eslint-config-prettier を入れて、競合を解消します。

$ npm install --save-dev eslint-config-prettier

.eslintrc.jsextends: ['prettier', を追加します。

.eslintrc.js
  extends: [
    'plugin:react/recommended',
    'airbnb',
    'airbnb-typescript',
    'prettier',
  ],

.eslintrc.js に extends prettier を追加


$ npx eslint src --ext .tsx --ext .ts

何も言われなくなりました!


$ npx eslint --print-config src/index.tsx で見ると、それぞれ、以下のように設定されたから解消されたようです。(単純に off になっています。)

react/jsx-one-expression-per-line
  "rules": {
    "react/jsx-one-expression-per-line": [
      "off",
      {
        "allow": "single-child"
      }
    ],
@typescript-eslint/comma-dangle
  "rules": {
    "@typescript-eslint/comma-dangle": [
      "off",
      {
        "arrays": "always-multiline",
        "objects": "always-multiline",
        "imports": "always-multiline",
        "exports": "always-multiline",
        "functions": "always-multiline",
        "enums": "always-multiline",
        "generics": "always-multiline",
        "tuples": "always-multiline"
      }
    ],
object-curly-newline
  "rules": {
    "object-curly-newline": [
      "off",
      {
        "ObjectExpression": {
          "minProperties": 4,
          "multiline": true,
          "consistent": true
        },
        "ObjectPattern": {
          "minProperties": 4,
          "multiline": true,
          "consistent": true
        },
        "ImportDeclaration": {
          "minProperties": 4,
          "multiline": true,
          "consistent": true
        },
        "ExportDeclaration": {
          "minProperties": 4,
          "multiline": true,
          "consistent": true
        }
      }
    ],

当然、今回確認しているエラー以外にも対応されていますが、省略します。


.ts.tsx の問題は解消されましたが、
.eslintrc.js
以下のエラーが表示されます。
Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: .eslintrc.js.
The file must be included in at least one of the projects provided.eslint

Parsing error


以下のように tsconfig.jsoninclude"./.eslintrc.js" を追加すると解消します。

"include": ["src", "./.eslintrc.js"]

Parsing error tsconfig.json 変更で解消


ただ、ESLint のエラーではないですが、
File is a CommonJS module; it may be converted to an ES module.ts(80001)
が指摘されます。

File is a CommonJS module


VSCode の settings.json に
"javascript.suggestionActions.enabled": false
を追加すると、解消します。

File is a CommonJS module settings.json 変更で解消


"include": ["src", "./.eslintrc.js"]
"javascript.suggestionActions.enabled": false
の対応以外でも .eslintrc.js の拡張子を json にすると、問題無くなります。


https://www.convertsimple.com/convert-javascript-to-json/ で JSON に変換して、 .eslintrc.js.eslintrc.json にすると、問題無くなります。今回その対応としました。

.eslintrc.json は、設定変更無しで認識されます。

convert-javascript-to-json


.eslintrc.json


Prettier(再び)

package.json に ESLint と Prettier のコマンドを書いて実行してみます。

package.json
    "lint:eslint": "eslint './{lib,src,test}/**/*.{ts,tsx}'",
    "lint-fix:prettier": "prettier --write './{lib,src,test}/**/*.{ts,tsx}'",

package.json に ESLint と Prettier のコマンド

$ npm run lint:eslint
$ npm run lint-fix:prettier
sh: 1: prettier: not found

VSCode で Prettier による、フォーマットが効くようになりましたが、現時点では、サーバー側で prettier を実行できません。 先ほど、VSCode で動いていた Prettier は、拡張機能にビルトインされた Prettier だからです。

Prettier と違い、ESLint の方は、VSCode 拡張機能の ESLint だけをインストールしても何も起きません。


prettier をインストールします。

$ npm install prettier
$ npm run lint-fix:prettier
src/App.test.tsx 318ms
src/App.tsx 18ms
src/index.tsx 13ms
src/react-app-env.d.ts 8ms
src/reportWebVitals.ts 19ms
src/setupTests.ts 5ms

今度は動いてフォーマットされましたが、まだ問題ありです。


先ほど、VSCode の settings.json に "prettier.singleQuote": true を設定したのに、サーバー側で設定していないため、
サーバー側:ダブルクォートが正解
VSCode 側:シングルクォートが正解
となっています。


サーバー側に .prettierrc.json というファイルを作成して、{ "singleQuote": true }を設定します。

.prettierrc.json
{ "singleQuote": true }

.prettierrc.json に singleQuote true


$ npm run lint-fix:prettier
src/App.test.tsx 318ms
src/App.tsx 18ms
src/index.tsx 13ms
src/react-app-env.d.ts 8ms
src/reportWebVitals.ts 19ms
src/setupTests.ts 5ms

これで、サーバーの prettier、VSCode の prettier で同じ結果になるはずです。

さらに、VSCode の prettier は、.prettierrc.json を見るため、settings.json の "prettier.singleQuote": true は消してしまっても構いません。

VSCode の settings.json prettier.singleQuote true 削除


また、

package.json

  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },

は、.eslintrc.json に移さないといけないですが、今回のソースコードでは、.eslintrc.json に移しても状況変らなかったため、"eslintConfig": 部分を package.json から削除しました。


手順まとめ

ここまで一歩一歩やってきましたが、下記の手順、設定で最後と同じ状況になります。

あくまで、create-react-app のソースコードを基準に調整しています。開発している内に対処が必要なことは考慮していません。


Node インストール

# apt update -y
# apt install -y gcc-multilib
# curl -fsSL https://deb.nodesource.com/setup_14.x | bash -
# apt update -y
# apt install -y nodejs
# node -v
# apt install -y npm
# npm i -g n yarn
# n install 14.16.0
# node -v
# PATH="$PATH"
# node -v
v14.16.0
# npm -v
6.14.11

VSCode SSH 接続

別記事 VS Code で Raspberry Pi Desktop へ SSH 接続しようとしたらエラーになった を参照してください。


React TypeScript プロジェクト作成

$ npx create-react-app sample-project --template typescript
$ cd sample-project

ESLint 対応

$ npx eslint --init

How would you like to use ESLint?
To check syntax, find problems, and enforce code style
What type of modules does your project use?
JavaScript modules (import/export)
Which framework does your project use?
React
Does your project use TypeScript?
Yes
Where does your code run?
Browser
How would you like to define a style for your project?
Use a popular style guide
Which style guide do you want to follow?
Airbnb: https://github.com/airbnb/javascript
What format do you want your config file to be in?
JSON
Would you like to install them now?
Yes
Which package manager do you want to use?
npm


npm install

$ npm install --save-dev eslint-config-airbnb-typescript eslint-config-prettier prettier

.eslintrc.json

.eslintrc.json
{
  "env": {
    "browser": true,
    "es2021": true
  },
  "extends": [
    "plugin:react/recommended",
    "airbnb",
    "airbnb-typescript",
    "prettier"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "ecmaVersion": "latest",
    "sourceType": "module",
    "project": "./tsconfig.json"
  },
  "plugins": ["react", "@typescript-eslint"],
  "rules": {}
}

VSCode 拡張機能インストール

Prettier インストール


ESLint インストール


settings.json

settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true
}

.prettierrc.json

.prettierrc.json
{ "singleQuote": true }

package.json

"lint:eslint": "eslint './{lib,src,test}/**/*.{ts,tsx}'",
"lint-fix:prettier": "prettier --write './{lib,src,test}/\*_/_.{ts,tsx}'"
追加

package.json
{
  "name": "sample-project",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/react": "^13.3.0",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^27.5.2",
    "@types/node": "^16.11.43",
    "@types/react": "^18.0.15",
    "@types/react-dom": "^18.0.6",
    "prettier": "^2.7.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "typescript": "^4.7.4",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "lint:eslint": "eslint './{lib,src,test}/**/*.{ts,tsx}'",
    "lint-fix:prettier": "prettier --write './{lib,src,test}/**/*.{ts,tsx}'"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^5.30.5",
    "@typescript-eslint/parser": "^5.30.5",
    "eslint": "^8.19.0",
    "eslint-config-airbnb": "^19.0.4",
    "eslint-config-airbnb-typescript": "^17.0.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-jsx-a11y": "^6.6.0",
    "eslint-plugin-react": "^7.30.1",
    "eslint-plugin-react-hooks": "^4.6.0"
  }
}

ESLint,Prettier 実行

$ npm run lint:eslint
$ npm run lint-fix:prettier

・Prettier
Prettier 動画


・ESLint
ESLint 動画

loading...