Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
19
Help us understand the problem. What is going on with this article?
@mizozobu

Next.js + TypeScriptの開発環境をVSCodeで整える(ESLint + Prettier + Husky + lint-staged + commitlint + EditorConfig)

ESLintとかPrettierとか設定が難しい

1年ぶりにフロントエンドに戻って来ると色々と変わっていました。具体的には...

このあたり本当によく変わりますよね。今回は以下のツールを設定して一流のNext.js + TypeScript開発環境の構築方法をまとめます。ESLintのところ以外はNext.jsでなくてもTypeScriptでなくても使えるはずです。

今後できれば更新していきたいです。

Changelog

  • Next.jsに寄せました(2021/06/26)。
  • Next.js 11で追加されたeslint-config-nextに対応しました(2021/07/10)。

Prettier

Prettierとは

PrettierはFormatter(コードを自動整形してくれるツール)です。

  • ""''
  • ()をつけるか
  • ,をつけるか
  • ...etc

といったスタイルを統一してくれます。

Prettierのインストールと設定

yarn add -D prettier

デフォルトの設定を上書きしたいところだけを設定ファイルに記載します。

.prettierrc
{
  "jsxSingleQuote": true,
  "singleQuote": true,
  "trailingComma": "all"
}

CIなどで使えるようにpackage.jsonにscirptを用意しておきます。

.package.json
"scripts": {
  "lint": "prettier --check .",
  "format": "prettier --write .",
  ...
},

VSCodeでファイル保存時にPrettierで自動整形する

さらにファイルを保存したタイミングで自動で整形するようにするために、Prettierのプラグインをインストールします。他の開発者のために推奨プラグインに記載しておきます。

.vscode/extensions.json
{
  "recommendations": [
    "esbenp.prettier-vscode",
  ]
}

VSCodeの設定ファイルを作成して、ファイルを保存したタイミングでPrettierで整形するように設定します。

.vscode/settings.json
{
  "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

同一パッケージの複数バージョンがnode_modulesにあるとESLintがどっちのバージョンを使えばよいかわからずエラーになることがあるのでeslint-config-nextのDependenciesと被っている物をアンインストールしておきます。

yarn remove @typescript-eslint/parser eslint-import-resolver-node eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-hooks

次にextendsに推奨設定を必要なものを入れていきます。

  • eslint-config-nextはNext.jsの<Link /><Image />の使い方のチェックをしてくれるので入れておいて損はないでしょう。 Next.js 11.0.0からCreate Next Appでデフォルトでインストールされます。
  • next/core-web-vitalsCore Web Vitalsの関連のチェックをしてくれます。
  • plugin:eslint/recommended, plugin:react/recommended, plugin:react-hooks/recommendedeslint-config-nextに含まれているので入れる必要は無いです(src)。
  • plugin:@typescript-eslint/eslint-recommendedplugin:@typescript-eslint/recommendedの両方を設定しているのも見かけますが、後者は前者をextendsしているので後者だけでよいでしょう(src)。
  • plugin:@typescript-eslint/recommended-requiring-type-checkingは型チェックをしてくれます。tscを実行しているようなものなのでチェックが遅くなりますが、入れておくべきでしょう。
  • eslint-config-airbnb-typescriptを採用するのもありだと思いますが、今回は見送っています。

結果、このような.eslintrc.jsになります。

.eslintrc.js
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
-   'plugin:react/recommended', // reactの設定はairbnbに任せます
+   'next', // next.js
+   'next/core-web-vitals', // Core Web Vitalsのチェック
    'airbnb',
+   'airbnb/hooks', // reactのhooksの設定は別れているので別途入れます
+   'plugin:@typescript-eslint/recommended', // typescriptの推奨設定を入れます
+   'plugin:@typescript-eslint/recommended-requiring-type-checking', // typescriptの型チェックをします
+   '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
.eslintignore
/.eslintrc.js

さらにTypeScriptのcompilerOptions.pathsのAliasをサポートするために一手間加えます。

yarn add -D eslint-import-resolver-typescript
.eslintrc.js
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    'next',
    'next/core-web-vitals',
    'airbnb',
    'airbnb/hooks',
    'plugin:@typescript-eslint/recommended',
    'plugin:@typescript-eslint/recommended-requiring-type-checking',
    '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設定済みのものを置いておきます。
.eslintrc.js
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    'next',
    'next/core-web-vitals',
    'airbnb',
    'airbnb/hooks',
    'plugin:@typescript-eslint/recommended',
    'plugin:@typescript-eslint/recommended-requiring-type-checking',
    '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を後にしています。

.package.json
"scripts": {
- "lint": "prettier --check .",
- "format": "prettier --write .",
+ "lint": "eslint . && prettier --check .",
+ "format": "eslint --fix . && prettier --write .",
  ...
},

VSCodeでファイル保存時にESLintで自動整形する

さらにファイルを保存したタイミングで自動で整形するようにするために、ESLintのプラグインをインストールします。他の開発者のために推奨プラグインに記載しておきます。

.vscode/extensions.json
{
  "recommendations": [
+   "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
  ]
}

VSCodeの設定ファイルにファイルを保存したタイミングでESLintで整形するように設定します。これでファイルを保存するのタイミングでPrettierとESLintの両方で整形されるようになります。

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

これでPrettierとESLintの設定が終わったので、yarn formatを実行しておくと良いです。

Husky + lint-staged

Huskyとは

HuskyGit Hooksを設定するツールです。

  • 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でチェックするようにします。

.lintstagedrc
{
  "**/*.{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
package.json
{
+ "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の設定ファイルを作成します。

commitlintrc.js
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のプラグインをインストールします。

他の開発者のために推奨プラグインに記載しておきます。

.vscode/extensions.json
{
  "recommendations": [
    "dbaeumer.vscode-eslint",
+   "editorconfig.editorconfig",
    "esbenp.prettier-vscode"
  ]
}

.editorconfigに設定を書きます。参考までにAngularの.editorconfigを置いておきます。大体はこれで十分です。

.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が突出していますね。このくらい凄い開発環境を実現するツールがが他の言語でもあるといいなと思います。

19
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
19
Help us understand the problem. What is going on with this article?