【Next.js】Next.js & TypeScript & ESLint, Prettier & husky Setup

# はじめに
`Next.js`のセットアップを紹介します。

続いて、`TypeScript`, `Eslint`, `Prettier`の設定もしていきます。

最後に、CIツールである`husky`を入れて、コミット時にテストを走らせる設定を追加していきます。

* 構築環境

| tools | version |
| :-- | :----: |
| Next.js | 13.0.0 |
| React | 18.2.0 |
| ESLint | 8.0.1 |
| Prettier | 2.7.1 |
| husky | 8.0.0 |

## 目次
1. [Next.js プロジェクトを作成](#nextjs-プロジェクトを作成)
2. [Eslint 初期設定](#eslint-初期設定)
3. [Prettier 設定](#prettier-設定)
4. [eslint-config-prettier 設定](#eslint-config-prettier-設定)
5. [エラー 解決](#エラー-解決)
6. [husky 導入](#husky-導入)

# Next.js プロジェクトを作成

何はともあれ、`Next.js`のプロジェクトを作成していきます。

プロジェクトを作成したいディレクトリで、下記コマンドを走らせます。

プロジェクトの作成と同時に、`TypeScript`も設定していきます。

`sample-app`の部分は自身のプロジェクト名を入れてください。

```
$ npx create-next-app sample-app --typescript
```
![スクリーンショット 2022-10-28 16.35.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619375/693d7bfa-5305-0caf-6c44-cb926959a786.png)



プロジェクトが作成できたら、プロジェクトのディレクトリに移動しておいてください。
念の為、サーバーが立ち上がることも確認しておきます。
```
$ cd sample-app

$ yarn dev
```

# Eslint 初期設定

`Eslint`の初期設定を行なっていきます。

```
$ npx eslint --init
```

設定について質問されるので、選択していきます。

- How would you like to use ESLint?
![スクリーンショット 2022-10-28 16.38.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619375/d130eec8-959d-6792-0cab-d7a190e9a609.png)

- What type of modules does your project use?
![スクリーンショット 2022-10-28 16.39.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619375/9fea8a15-17b1-ae5d-878d-a4c60488a48d.png)


- Which framework does your project use?
![スクリーンショット 2022-10-28 16.39.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619375/699ca080-5be4-dc75-a3c7-3b44340ea359.png)


- Does your project use TypeScript?
![スクリーンショット 2022-10-28 16.39.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619375/b4d31333-7b95-118a-8b21-c006503fe63e.png)


- Where does your code run?
![スクリーンショット 2022-10-28 16.40.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619375/cd90af56-e28c-9a91-d356-84c8932226e0.png)


- How would you like to define a style for your project?
![スクリーンショット 2022-10-28 16.41.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619375/7fd152df-4ad3-f463-2ede-175b08097113.png)


- Which style guide do you want to follow?
![スクリーンショット 2022-10-28 16.41.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619375/c1efc210-fa32-a57c-df4f-22126f128b58.png)
今回は、Standardを選択しています。1番厳しいstyle guideとして、airbnbを選択することもあります。

- What format do you want your config file to be in?
![スクリーンショット 2022-10-28 16.41.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619375/284c8af3-7298-6ca3-58c2-c6d65ba7efbb.png)

今回はJavaScriptを選択していますが、お好きなものを選択してください。

- Would you like to install them now?
![スクリーンショット 2022-10-28 16.42.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619375/1bdfa43e-8c72-ade4-f278-de9738da2b82.png)

- Which package manager do you want to use?
![スクリーンショット 2022-10-28 16.43.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619375/be2d70a4-24fd-1c4a-99e9-1b95633adca8.png)


すべて選択した後に、このようになっていれば設定完了です。

![スクリーンショット 2022-10-28 16.47.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619375/cdf49fb5-8b81-6379-7178-6313d7bee446.png)

設定が完了できたら、`.eslintrc.js`が作成されていることを確認してください。

```
sample-app
  ├── .next
  ├── node_modules
  ~
+ └── .eslintrc.js
```

`.eslintrc.js`を編集していきます。

`React`のバージョンを指定することで、`Eslint`がそのルールに合わせてくれます。

今回は`React`のバージョンを`18.2.0`に設定していますが、`latest`でも大丈夫です。

(`latest`に設定した場合、今後`husky`を動かした際に`WARINING`がでます)

```.eslintrc.js
  module.exports = {
    env: {
      browser: true,
      es2021: true,
    },
    extends: ['plugin:react/recommended', 'standard-with-typescript'],
    overrides: [],
    parserOptions: {
      ecmaVersion: 'latest',
      sourceType: 'module',
    },
    plugins: ['react'],
    rules: {
      'react/react-in-jsx-scope': 'off',
    },
+   settings: {
+     react: {
+       version: '18.2.0',
+     },
    },
  };
```

次に、`.eslintignore`ファイルを作成します。

```
$ touch .eslintignore
```
```
sample-app
  ├── .next
  ├── node_modules
  ~
  ├── .eslintrc.js
+ └── .eslintignore
```
作成後、`.eslintignore`を編集していきます。

編集する中身についてはご自身のプロジェクトによって変わると思いますので、今回は参考として例を載せておきます。

```.eslintignore
.next
next-env.d.ts
node_modules
yarn.lock
package-lock.json
public
```

# Prettier 設定

`Prettier`を導入していきます。

下記コマンドを入力して開発環境に`Prettier`を入れてください。

```
$ yarn add --dev prettier
```

導入が完了したら、`.prettierrc`ファイルを作成します。
```
$ touch .prettierrc
```
```
sample-app
  ├── .next
  ├── node_modules
  ~
  ├── .eslintrc.js
  ├── .eslintignore
+ └── .prettierrc
```

作成後、`.prettierrc`を編集していきます。

編集する中身についてはご自身のプロジェクトによって変わると思いますので、今回は参考として例を載せておきます。

```.prettierrc
{
  "endOfLine": "lf",
  "printWidth": 80,
  "tabWidth": 2,
  "trailingComma": "es5",
  "singleQuote": true,
  "jsxSingleQuote": true,
  "semi": true
}
```

続いて、`.prettierignore`ファイルを作成します。

```
$ touch .prettierignore
```
```
sample-app
  ├── .next
  ├── node_modules
  ~
  ├── .eslintrc.js
  ├── .eslintignore
  ├── .prettierrc
+ └── .prettierignore
```
作成後、`.prettierignore`を編集していきます。

`.prettierignore`の中身については`.eslintignore`と同じにしておきます。

こちらもご自身のプロジェクトに合わせて編集してください。

```.prettierignore
.next
next-env.d.ts
node_modules
yarn.lock
package-lock.json
public
```

# eslint-config-prettier 設定

下記コマンドを入力して、`eslint-config-prettier`を導入していきます。

`Eslint`にもコードフォーマット機能がすでにあるのですが、`Prettier`にコードフォーマットを任せるので、競合を防ぐために、`eslint-config-prettier`が必要になります。

```
$ yarn add --dev eslint-config-prettier
```

導入が完了したら、`.eslintrc.js`を編集していきます。

`extends`に`prettier`を追加しました。

**`prettier`の追加は、`extends`内の最後に追加しないと設定が上書きされないことに注意してください。**

```.eslintrc.js
  module.exports = {
    env: {
      browser: true,
      es2021: true,
    },
    extends: [
      'plugin:react/recommended', 
      'standard-with-typescript', 
+     'prettier'
    ],
    overrides: [],
    parserOptions: {
      ecmaVersion: 'latest',
      sourceType: 'module',
    },
    plugins: ['react'],
    rules: {
      'react/react-in-jsx-scope': 'off',
    },
    settings: {
      react: {
        version: '18.2.0',
      },
    },
  };
```

以上で、`TypeScript`, `Eslint`, `Prettier`の設定が完了しました。

`package.json`ファイルの中身を確認しておきましょう。

```package.json
{
  "name": "nextjs-front-sample",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "next": "13.0.0",
    "react": "18.2.0",
    "react-dom": "18.2.0"
  },
  "devDependencies": {
    "@types/node": "18.11.7",
    "@types/react": "18.0.24",
    "@types/react-dom": "18.0.8",
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "eslint": "^8.0.1",
    "eslint-config-next": "13.0.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-config-standard-with-typescript": "^23.0.0",
    "eslint-plugin-import": "^2.25.2",
    "eslint-plugin-n": "^15.0.0",
    "eslint-plugin-promise": "^6.0.0",
    "eslint-plugin-react": "^7.31.10",
    "prettier": "^2.7.1",
    "typescript": "*",
  }
}
```

`TypeScript`, `Eslint`, `Prettier`の設定完了と言いたいところですが、後述する`husky`を設定し走らせたときに、エラーが返ってきたので`husky`を導入しない人のために先にエラーを解決していきます。

# エラー 解決
```
$ ~
$ ~
$ Oops! Something went wrong! :(

$ ESLint: 8.26.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.
$ ~
```
エラーの内容としては、parserOptions.projectにプロパティを入れてねって言われています。

`.eslintrc.js`を編集していきます。

```.eslintrc.js
  module.exports = {
    env: {
      browser: true,
      es2021: true,
    },
    extends: ['plugin:react/recommended', 'standard-with-typescript', 'prettier'],
    overrides: [],
    parserOptions: {
      ecmaVersion: 'latest',
      sourceType: 'module',
+     project: './tsconfig.json',
    },
    plugins: ['react'],
    rules: {
      'react/react-in-jsx-scope': 'off',
    },
    settings: {
      react: {
        version: '18.2.0',
      },
    },
  };
```

これで`tsconfig.json`のルールに沿って`Eslint`が走ってくれるので、エラーは解決します。

以上で、`TypeScript`, `Eslint`, `Prettier`の設定完了となります。

# husky 導入

下記コマンドを入力して、`husky`を導入していきます。

```
$ npx husky-init
```

導入ができたら、`.husky`フォルダが作成されていることを確認してください。

```
sample-app
  ├── .next
  ├── node_modules
  ~
  └── .husky
       ├── pre-commit
       └── _
            ├── .gitignore
            └── husky.sh
```

`pre-commit`を編集していきます。

これを編集することで、コミット時にテストを走らせることができます。
今回は参考として例を載せておきます。

```pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

# bash echo color
RED='\033[1;31m'
GREEN='\033[1;32m'
BLUE='\033[1;36m'
BOLD='\033[1;37m'
NC='\033[0m'

echo "\n ${BOLD}Checking format, lint and types in your project before committing${NC}"

# Check Prettier standards
npm run check-format ||
(
    echo "\n Prettier Check ${RED}Failed${NC}. \n Run ${BLUE}npm run format${NC}, add changes and try commit again.\n";
    false;
)

# Check ESLint Standards
npm run check-lint ||
(
    echo "\n ESLint Check ${RED}Failed${NC}. \n Make the required changes listed above, add changes and try to commit again.\n"
    false;
)

# Check tsconfig standards
npm run check-types ||
(
    echo "\n Type check ${RED}Failed${NC}. \n Make the changes required above.\n"
    false;
)

# If everything passes... Now we can build
echo "${BOLD}All passed... Now we can build.${NC}"

npm run build ||
(
    echo "\n Next build ${RED}Failed${NC}. \n View the errors above to see why.\n"
    false;
)

# If everything passes... Now we can commit
echo "${GREEN}Build is completed... I am committing this now.${NC} \n"
```

続いて、`husky`を走らせるコマンドを設定するために、`package.json`を編集しておきます。

```package.json
  {
    "name": "nextjs-front-sample",
    "version": "0.1.0",
    "private": true,
    "scripts": {
      "dev": "next dev",
      "build": "next build",
      "start": "next start",
      "lint": "next lint",
      "prepare": "husky install",
+     "check-types": "tsc --pretty --noEmit",
+     "check-format": "prettier --check .",
+     "check-lint": "eslint . --ext ts --ext tsx --ext js",
+     "format": "prettier --write .",
+     "test-all": "npm run check-format && npm run check-lint && npm run check-types"
    },
    "dependencies": {
      "next": "13.0.0",
      "react": "18.2.0",
      "react-dom": "18.2.0"
    },
    "devDependencies": {
      "@types/node": "18.11.7",
      "@types/react": "18.0.24",
      "@types/react-dom": "18.0.8",
      "@typescript-eslint/eslint-plugin": "^5.0.0",
      "eslint": "^8.0.1",
      "eslint-config-next": "13.0.0",
      "eslint-config-prettier": "^8.5.0",
      "eslint-config-standard-with-typescript": "^23.0.0",
      "eslint-plugin-import": "^2.25.2",
      "eslint-plugin-n": "^15.0.0",
      "eslint-plugin-promise": "^6.0.0",
      "eslint-plugin-react": "^7.31.10",
      "prettier": "^2.7.1",
      "typescript": "*",
      "husky": "^8.0.0"
    }
  }
```

これで`husky`の設定も完了しました。

Git Hubにコミットをした際に`husky`が走るようになります。
```
$ git commit -m "xxxxxx"
```

テストにパスすればコミットが成功します。

# 最後に
以上、`Next.js`の環境構築に加えて、`TypeScript`, `Eslint`, `Prettier`, `husky`の導入について紹介しました。

フロントの技術は日進月歩なので、やり方が古いや間違ってるといったことがあればコメントで教えてください。

最後まで読んでいただきありがとうございました。

# 参照

- [React reference](https://ja.reactjs.org/docs/getting-started.html)
- [ESLint reference](https://eslint.org/docs/latest/)
- [Prettier reference](https://prettier.io/docs/en/index.html)
- [husky](http://typicode.github.io/husky/#/)