ESLintとかPrettierとか設定が難しい
1年ぶりにフロントエンドに戻って来ると色々と変わっていました。具体的には...
- eslint-config-prettierが非推奨になっていた
- huskyがv6になって動かなくなっていた
このあたり本当によく変わりますよね。今回は以下のツールを設定して一流のNext.js + TypeScript開発環境の構築方法をまとめます。ESLintのところ以外はNext.jsでなくてもTypeScriptでなくても使えるはずです。
今後できれば更新していきたいです。
Changelog
- Next.jsに寄せました(2021/06/26)。
- Next.js 11で追加されたeslint-config-nextに対応しました(2021/07/10)。
- ESLintの設定をNext.jsの公式に従った形に修正しました(2021/09/17)
Prettier
Prettierとは
PrettierはFormatter(コードを自動整形してくれるツール)です。
-
""か'' -
()をつけるか -
,をつけるか - ...etc
といったスタイルを統一してくれます。
Prettierのインストールと設定
yarn add -D prettier
デフォルトの設定を上書きしたいところだけを設定ファイルに記載します。
{
"jsxSingleQuote": true,
"singleQuote": true,
"trailingComma": "all"
}
CIなどで使えるようにpackage.jsonにscirptを用意しておきます。
"scripts": {
"lint": "prettier --check .",
"format": "prettier --write .",
...
},
VSCodeでファイル保存時にPrettierで自動整形する
さらにファイルを保存したタイミングで自動で整形するようにするために、Prettierのプラグインをインストールします。他の開発者のために推奨プラグインに記載しておきます。
{
"recommendations": [
"esbenp.prettier-vscode",
]
}
VSCodeの設定ファイルを作成して、ファイルを保存したタイミングでPrettierで整形するように設定します。
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
}
ここでyarn formatを実行して何が整形されるか見ておくとESLintとの違いがわかりやすいかもしれません。
ESLint
ESLintとは
ESLintはLinter(コードの品質チェックをするツール)です。
- 使われていない変数は無いか
- 意図せずにglobal変数になっている変数は無いか
-
===の代わりに==が使われていないか - ...etc
といった品質チェックをしてくれます。チェックした後に自動修正もできるのでPrettierとの役割分担が曖昧になりがちです。
これまではeslint-config-prettierを使って、ESLintからPrettierを実行する手法が一般的でしたが、この方法は非推奨になりました。
これからはPrettierでFormatをして、ESLintで品質チェックをするように役割を分担して、競合する部分はPrettierにやらせるようにするようです。
ESLintのインストールと設定
yarn add -D eslint
ESLintの初期設定はCLIを使うと簡単です。
yarn eslint --init
✔ 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, node
✔ 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
次にextendsに推奨設定を必要なものを入れていきます。
-
plugin:@typescript-eslint/eslint-recommendedとplugin:@typescript-eslint/recommendedの両方を設定しているのも見かけますが、後者は前者をextendsしているので後者だけでよいでしょう(src)。 -
plugin:@typescript-eslint/recommended-requiring-type-checkingは型を必要とするルールを有効化します。tscを実行しているようなものなのでチェックが遅くなりますが、入れておくべきでしょう。 - eslint-config-airbnb-typescriptを採用するのもありだと思いますが、今回は見送っています。
-
plugin:@next/next/recommendedはNext.jsの<Link />や<Image />の使い方のチェックをしてくれるので入れておいて損はないでしょう。 -
plugin:@next/next/core-web-vitalsはCore Web Vitalsの関連のチェックをしてくれます。plugin:@next/next/recommendedを継承しているので、これを採用する場合はplugin:@next/next/recommendedは必要ありません。
必要なものを追加インストールします。
yarn add -D eslint-config-prettier @next/eslint-plugin-next
ESLintのextendsは後ろのものほど優先されるので、prettierを最後尾に、その前にnext.js関連を持ってきます。結果、このような.eslintrc.jsになります。
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
- 'plugin:react/recommended', // reactの設定はairbnbに任せます
'airbnb',
+ 'airbnb/hooks', // reactのhooksの設定は別れているので別途入れます
+ 'plugin:@typescript-eslint/recommended', // typescriptの推奨設定を入れます
+ 'plugin:@typescript-eslint/recommended-requiring-type-checking', // typescriptの型チェックをします
+ 'plugin:@next/next/core-web-vitals', // Next.jsとCore Web Vitalsのチェック
+ 'prettier', // prettierと競合するESLintのルールを無効化します
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
+ project: './tsconfig.json', // plugin:@typescript-eslint/recommended-requiring-type-checkingの参照するtsconfig
sourceType: 'module',
},
plugins: ['react', '@typescript-eslint'],
rules: {},
};
これでは.eslintrc.jsがに対してこのようなエラーが出てしまうので、.eslintignoreを作成して.eslintrc.js自体をESLintのチェックから除外します。
0:0 error 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
/.eslintrc.js
さらにTypeScriptのcompilerOptions.pathsのAliasをサポートするために一手間加えます。
yarn add -D eslint-import-resolver-typescript
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
'airbnb',
'airbnb/hooks',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:@next/next/core-web-vitals',
'prettier',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
project: './tsconfig.json',
sourceType: 'module',
},
plugins: ['react', '@typescript-eslint'],
rules: {},
+ settings: { // typescriptのaliasがエラーにならないように
+ 'import/resolver': {
+ typescript: {
+ project: './tsconfig.json',
+ },
+ },
+ },
};
後はエラーを消すために独断と偏見でrulesを設定してください(これが少し面倒)。
余計なものも入ってますが、参考までに`rules`設定済みのものを置いておきます。
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
'airbnb',
'airbnb/hooks',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:@next/next/core-web-vitals',
'prettier',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
project: './tsconfig.json',
sourceType: 'module',
},
plugins: ['react', '@typescript-eslint'],
rules: {
// hush no-use-before-define error in "import React from 'react';"
// see https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-use-before-define.md#how-to-use
'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': ['error'],
// omit .ts .tsx in import statement
// see https://stackoverflow.com/questions/59265981/typescript-eslint-missing-file-extension-ts-import-extensions
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
},
],
// allow named exports without default export
'import/prefer-default-export': 'off',
// allow importing storybooks from devDependencies
// see https://github.com/storybookjs/storybook/issues/1992#issuecomment-335001056
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: ['.storybook/**', '**/*.stories.tsx'],
},
],
// allow jsx in .tsx
'react/jsx-filename-extension': [1, { extensions: ['.jsx', '.tsx'] }],
// nextjs does not need React in every file
'react/react-in-jsx-scope': 'off',
// use this pattern for default props
//
// interface Props {
// prop1?: boolean;
// }
// const Component1: FC<Props> = ({ prop1 = false }: Props) => (
// <Component1 prop1={prop1} />
// );
'react/require-default-props': 'off',
// allow <App {...props} />
'react/jsx-props-no-spreading': 'off',
},
settings: {
'import/resolver': {
typescript: {
project: './tsconfig.json',
},
},
},
};
CIなどで使えるようにpackage.jsonにscirptを用意しておきます。ESLintで;が追加された後にPrettierのprintWidthを超えた場合などに備えてPrettierを後にしています。
"scripts": {
- "lint": "prettier --check .",
- "format": "prettier --write .",
+ "lint": "eslint . && prettier --check .",
+ "format": "eslint --fix . && prettier --write .",
...
},
VSCodeでファイル保存時にESLintで自動整形する
さらにファイルを保存したタイミングで自動で整形するようにするために、ESLintのプラグインをインストールします。他の開発者のために推奨プラグインに記載しておきます。
{
"recommendations": [
+ "dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
]
}
VSCodeの設定ファイルにファイルを保存したタイミングでESLintで整形するように設定します。これでファイルを保存するのタイミングでPrettierとESLintの両方で整形されるようになります。
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.codeActionsOnSave": {
+ "source.fixAll.eslint": true
+ },
}
これでPrettierとESLintの設定が終わったので、yarn formatを実行しておくと良いです。
Husky + lint-staged
Huskyとは
- commitの前に~する
- pushの前に~する
- commit messageに対して~する
- ...etc
ということが設定できます。
lint-stagedとは
lint-stagedはstageされたファイルだけを操作するためのツールです。Huskyと併用することで、commitされるファイルに対してだけPrettierやESLintのチェックをするということができるようになります。
lint-stagedのインストールと設定
yarn add -D lint-staged
先にlint-stagedの設定をします。stageされているファイルに対してESLintでチェックした後にPrettierでチェックするようにします。
{
"**/*.{js,jsx,ts,tsx}": [
"yarn eslint",
"yarn prettier --check"
]
}
正しく設定されているか確認するにはjs, jsx, ts, tsxのファイルをstageして以下のコマンドを実行します。
yarn lint-staged
Huskyのインストールと設定
次にHuskyの設定をします。
yarn add -D husky
hasky@4までは.huskyrcを作成すれば良かったのですが、hasky@6ではかなり変わっているので注意が必要です。
hasky@6ではyarnとyarn v2ではインストール方法が違いますが、v2の方法でやってもv1のままで動くので、今後の事を考えてv2の手動の方法でやっておけばよいでしょう。
yarn husky install
{
+ "private": true,
+ "scripts": {
+ "postinstall": "husky install"
+ },
...
}
pre-commit hookでyarn lint-stagedを実行するようにします。
yarn husky add .husky/pre-commit "yarn lint-staged"
commitlint
commitlintとは
Gitのcommit messageにもルールを設定できるのが、commitlintです。ライブラリーのcommit messageによくあるこういうやつです。
chore: upgrade xxxx
docs: update README.md
どういうルールにするかは自分で設定できますが、よく使うルールは用意されています。
@commitlint/config-conventionalでだいたいの場合は事足りるので今回はこれで行きます。
commitlintのインストールと設定
yarn add -D @commitlint/config-conventional @commitlint/cli
commitlintの設定ファイルを作成します。
module.exports = {
extends: ['@commitlint/config-conventional'],
};
Huskyでcommit-msg hookでcommitlintを実行するように設定します。
yarn husky add .husky/commit-msg 'yarn commitlint --edit "$1"'
これで変なcommit messageでcommitしようとすると弾かれることが確認できます。
EditorConfig
EditorConfigとは
世の中にはJetBrainsの熱烈なファンがいたり、Vimマスターがいたりと、すべての開発者がVSCodeを使っているわけではありません。環境が違えば色々と違いがあり...
- ファイルの最終行に空行を入れるか
- インデントはタブなのかスペース2個なのか
- 改行コードはLFなのかCRLFなのか
などの個人のIDEの設定によってバラバラだったりします。そんなときに登場するのがEditorConfigです。
EditorConfigのインストールと設定
導入は簡単で、ますIDEでEditorConfigのプラグインをインストールします。
他の開発者のために推奨プラグインに記載しておきます。
{
"recommendations": [
"dbaeumer.vscode-eslint",
+ "editorconfig.editorconfig",
"esbenp.prettier-vscode"
]
}
.editorconfigに設定を書きます。参考までにAngularの.editorconfigを置いておきます。大体はこれで十分です。
# https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
まとめ
かなりガチガチなReact + TypeScript開発環境ができました。これで余計なところに気を取られずに開発やレビューに集中できますね。
開発環境ツールに関しては他の言語に比べてJavaScriptが突出していますね。このくらい凄い開発環境を実現するツールがが他の言語でもあるといいなと思います。