- 記事一覧 >
- ブログ記事
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 拡張機能のみインストール済みとします。
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
に接続してみます。
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
に対応していなくて、これではまだ設定が足りていないからです。
extends: [
'plugin:react/recommended',
'airbnb',
],
airbnb の TypeScript 拡張設定 を適用します。
$ npm install --save-dev eslint-config-airbnb-typescript
'airbnb-typescript',
を追加します。
extends: [
'plugin:react/recommended',
'airbnb',
'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',
を追加します。
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 'latest',
sourceType: 'module',
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
で見ると、それぞれ、以下のように設定されたから解消されたようです。
"settings": {
"import/resolver": {
"node": {
"extensions": [
".mjs",
".js",
".jsx",
".json",
".ts",
".tsx",
".d.ts"
]
}
},
"rules": {
"import/no-unresolved": [
"off",
{
"commonjs": true,
"caseSensitive": true,
"caseSensitiveStrict": false
}
],
"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"
}
],
"rules": {
"no-undef": [
"off"
],
"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 をインストールします。
設定 → リモート [SSH: 192.168.11.6] → 設定 (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.js
の extends: [
に 'prettier',
を追加します。
extends: [
'plugin:react/recommended',
'airbnb',
'airbnb-typescript',
'prettier',
],
$ npx eslint src --ext .tsx --ext .ts
何も言われなくなりました!
$ npx eslint --print-config src/index.tsx
で見ると、それぞれ、以下のように設定されたから解消されたようです。(単純に off になっています。)
"rules": {
"react/jsx-one-expression-per-line": [
"off",
{
"allow": "single-child"
}
],
"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"
}
],
"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
以下のように tsconfig.json
の include
に "./.eslintrc.js"
を追加すると解消します。
"include": ["src", "./.eslintrc.js"]
ただ、ESLint のエラーではないですが、File is a CommonJS module; it may be converted to an ES module.ts(80001)
が指摘されます。
VSCode の settings.json に"javascript.suggestionActions.enabled": false
を追加すると、解消します。
"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
は、設定変更無しで認識されます。
Prettier(再び)
package.json に ESLint と Prettier のコマンドを書いて実行してみます。
"lint:eslint": "eslint './{lib,src,test}/**/*.{ts,tsx}'",
"lint-fix:prettier": "prettier --write './{lib,src,test}/**/*.{ts,tsx}'",
$ 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 }
を設定します。
{ "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
は消してしまっても構いません。
また、
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
{
"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 拡張機能インストール
settings.json
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
}
.prettierrc.json
{ "singleQuote": true }
package.json
"lint:eslint": "eslint './{lib,src,test}/**/*.{ts,tsx}'",
"lint-fix:prettier": "prettier --write './{lib,src,test}/\*_/_.{ts,tsx}'"
追加
{
"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
その他、宣伝、誹謗中傷等、当方が不適切と判断した書き込みは、理由の如何を問わず、投稿者に断りなく削除します。
書き込み内容について、一切の責任を負いません。
このコメント機能は、予告無く廃止する可能性があります。ご了承ください。
コメントの削除をご依頼の場合はTwitterのDM等でご連絡ください。