【個人開発_#1】Next.js+TypeScript+Tailwind+ESlint+Prettierで開発環境を整えてみる #1

## はじめに
個人開発でWebサービスを作りたいと思い、せっかくなので流行りのNext.jsを使って構築を行うことにしました。
開発の備忘録としてQiitaに投稿していこうと思います。

## 環境
| ツール名 | バージョン |
|:-:|:-:|
|  VSCode |  1.90.0 |
| Node.js  |  20.14.0 |
| pnpm  | 9.4.0  |


## Next.jsでプロジェクトの作成
まずは、Next.jsをインストールします。業務で`pnpm`を使うことが増えてきたので今回プライベートでも使ってみます。
```zsh
pnpm create next-app@latest
```
いくつか質問されるので、デフォルトの設定で進めます。
```zsh
✔ What is your project named? … nextjs-jocv
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
```

## TypeScriptの設定
他の方の記事を参考に一部`tsconfig.json`の中身を書き換えてみました。
```diff:tsconfig.json
{
  "compilerOptions": {
    "lib": ["dom", "dom.iterable", "esnext"],
+   "allowJs": false,
-   "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
+   "forceConsistentCasingInFileNames": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

```
### "allowJs": false
falseにすることで`.js`、`.jsx`をコンパイル対象外とすることができます。

### "forceConsistentCasingInFileNames": true
ファイル名の大文字と小文字を区別することができます。

参考記事

https://zenn.dev/t_keshi/scraps/9ddb388bc6975d

## ESLintの設定
TypeScriptの構文チェックのためにESLintを使用します。
初期の設定を確認します。

```pacakge.json
{
  "scripts": {
    ・・・
    "lint": "next lint"
  },
  ・・・
  "devDependencies": {
    ・・・
    "eslint": "^8",
    "eslint-config-next": "14.2.4"
  }
}
```
```.eslintrc.json
{
  "extends": "next/core-web-vitals"
}
```
### ESLintの推奨ルールの設定
```diff:.eslintrc.json
{
-  "extends": ["next/core-web-vitals"],
+  "extends": ["eslint:recommended","next/core-web-vitals"],
}

```
`next/core-web-vitals`はNext.jsのコアWebバイタルに関連するパフォーマンスやアクセシビリティの改善に焦点をあてているようです。
`eslint:recommended`を追加することで、一般的なJavaScriptのベストプラクティスに基づいたルールに合わせることができるようです。

`eslint:recommended`に設定されている内容は下記になります。

https://eslint.org/docs/latest/rules/

### Tailwindの設定
以前、これを導入する前は「クラスの順番がめちゃくちゃ気持ち悪いな」と思っていましたが、こちらで解決できました。

https://github.com/francoismassart/eslint-plugin-tailwindcss

```bash
$ pnpm add -D eslint-plugin-tailwindcss
```
インストール後に、`.eslintrc.json`に追加してあげましょう。
```diff:.eslintrc.json
"extends": [
    "eslint:recommended",
    "next/core-web-vitals",
+   "plugin:tailwindcss/recommended"
],
```

### Prettierと衝突するルールの無効化
後ほど設定するPrettierとESLintのルールがバッティングする可能性があるので回避するために`eslint-config-prettier`を追加します。

```bash
pnpm add -D eslint-config-prettier
```
```diff:.eslintrc.json
"extends": [
    "eslint:recommended",
    "next/core-web-vitals",
    "plugin:tailwindcss/recommended"
+   "prettier"
],
```

:::note
extendsでは後に指定したルールが前のルールを上書きします。
:::

### 不要なimpoertの削除"unused-imports/no-unused-imports"
```bash
pnpm add -D eslint-plugin-unused-imports
```
```diff:.eslintrc.json
{
+  "plugins": ["import","unused-imports"],
+  "rules": {
+    "unused-imports/no-unused-imports": "error"
+  }
}
```

### importの重複を削除"unused-imports"
```bash
pnpm add -D eslint-plugin-import 
```

```diff:.eslintrc.json
{
+  "plugins": ["import","unused-imports"],
+  "rules": {
+    "unused-imports/no-unused-imports": "error"
+  }
}
```

おそらくもう少し細かく設定したほうがよかったりするのでしょうが、今回は自分で調べたものだけを入れようと決めたのでこの辺にしておきます。
実装中に何か追加した際にはこちらに追加していきます。

## Prettierの設定
Prettierを導入して自動整形行います。
整形は人間やるものではないと思うので自動化しておきます。
### Prettierのインストール
```bash
pnpm add -D prettier
```

### Prettierの設定
`.prettierrc.json`を作成します。

```.prettierrc.json
{
  "printWidth": 120,
  "singleQuote": true
}
```
### "printWidth"
折り返し幅です。デフォルトが80ですが、広めが好きなので120に設定しています。

### "singleQuote"
文字列をダブルクォーテーションで囲みます。

### .prettierignoreの設定
`.gitignore`で指定されたファイルは対象外としてくれますが、追加で除外したい時にはファイルを作成して追加します。

```.prettierignore
/package-lock.json
```

### VSCodeの設定
ファイル保存時に自動でフォーマットされて欲しいのでVSCodeの拡張機能を入れます。

https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode

`.vscode/settings.json`を作成して下記のように追加します。
```.vscode/settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode", // Prettierをフォーマッターとして設定
  "editor.formatOnSave": true,
}
```

## Husky + lint-stagedの設定
こちらは別の記事でまとめました。こちらを参照ください。

https://qiita.com/okalog/items/618b24e9adba6c001c0f

## commitlintの設定
個人開発ですが、コミットメッセージにも一定のルールを持たせるために、commitlintを導入しました。これにより、コミットメッセージが一貫性を持ち、プロジェクトの履歴が整理されやすくなります。

https://github.com/conventional-changelog/commitlint
### commitlintのインストール
まず、commitlintをプロジェクトにインストールします。以下のコマンドを使用します。
```bash
pnpm add -D @commitlint/{cli,config-conventional}
```
### commitlintの設定ファイルを作成
次に、commitlintの設定ファイルを作成します。以下のコマンドを実行して、commitlint.config.jsファイルをプロジェクトのルートに作成します。

また、今回はprefixにgitmojiを採用してみました。今までfeat:やfix:を使ってきましたが絵文字可愛いし使ってみようというモチベーションです。

```bash
echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
```
### Huskyフックの設定
次に、Huskyを使用してコミットメッセージを検証するフックを設定します。以下のコマンドを実行して、commit-msgフックを作成します。
これにより、コミットメッセージが作成されるたびにcommitlintが自動的に実行され、メッセージがルールに従っているかどうかをチェックします。
```bash
echo "pnpm dlx commitlint --edit \$1" > .husky/commit-msg
```

`commitlint.config.js`はcommitlintの設定を管理する主要なファイルです。
このファイルで、どのルールを適用するか、カスタムプラグインをどのように組み込むかを定義します。
```commitlint.config.js
const customPlugin = require('./commitlint-plugin-custom');

module.exports = {
  extends: ['@commitlint/config-conventional'],
  plugins: [
    {
      rules: customPlugin.rules,
    },
  ],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        '🐛', // バグ修正・誤字脱字修正
        '✏️', // 微修正
        '✨', // 新機能・新ファイル追加
        '🎉', // 新プロジェクト立ち上げ
        '⚡️', // 改良・高速化
        '♻️', // コード整形
        '💩', // 非推奨追加
        '🗑️', // 削除
      ],
    ],
    'subject-case': [0], // ケースを強制しない
    'type-case': [0], // タイプのケースを強制しない
    'type-empty': [0], // タイプの空を許可する
    'subject-empty': [0], // サブジェクトの空を許可する
    'header-match-pattern': [2, 'always'],
  },
};
```
カスタムプラグイン`commitlint-plugin-custom.js`は、独自のバリデーションルールを定義するために使用します。
別ファイルに切り出さないとエラーが出てしまっていたので切り出しました。

```commitlint-plugin-custom.js
module.exports = {
  rules: {
    'header-match-pattern': ({ header }) => {
      const pattern = /^(🐛|✏️|✨|🎉|⚡️|♻️|💩|🗑️):\s.+$/;
      return [pattern.test(header), 'header must start with one of the custom emojis followed by ": " and a subject'];
    },
  },
};
```
この設定により下記のようなコメントのみ許容されるようになります。

```
🎉: init
🐛: Fix custom hook
```
もう少しここは設定凝ることができそうなので開発の中でアップデートしていけたらと思います。

## VSCodeの設定
VSCodeの拡張を入れています。
`.vscode/settings.json`の中で設定したものを共有しておきます。
```.vscode/settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode", // Prettierをフォーマッターとして設定
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit", // ファイル保存時にESLintの自動修正を実行する
    "source.addMissingImports": "explicit" // 未importのモジュールを自動で探してimport文を追加する
  },
  "gitmoji.addCustomEmoji": [
    {
      "emoji": "🐛",
      "code": ":bug:",
      "description": "バグ修正・誤字脱字修正"
    },
    {
      "emoji": "✏️",
      "code": ":pencil2:",
      "description": "微修正"
    },
    {
      "emoji": "✨",
      "code": ":sparkles:",
      "description": "新機能・新ファイル追加"
    },
    {
      "emoji": "🎉",
      "code": ":tada:",
      "description": "新プロジェクト立ち上げ"
    },
    {
      "emoji": "⚡️",
      "code": ":zap:",
      "description": "改良・高速化"
    },
    {
      "emoji": "♻️",
      "code": ":recycle:",
      "description": "コード整形"
    },
    {
      "emoji": "💩",
      "code": ":poor:",
      "description": "非推奨追加"
    },
    {
      "emoji": "🗑️",
      "code": ":wastebasket:",
      "description": "削除"
    }
  ],
  "gitmoji.onlyUseCustomEmoji": true
}
```
### gitmoji
今回gitmojiを初めて入れてみたけど、結構使い勝手が良さそうです。
![CleanShot 2024-06-21 at 09.34.29@2x.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592040/a05a8424-a737-2d7a-f678-42e969c7d04a.jpeg)
ただ見ての通り、絵文字が多すぎてそんないらねぇーよとなったのでカスタム絵文字として登録しました。
![CleanShot 2024-06-21 at 09.33.25@2x.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592040/347b74da-bac4-d3ea-32bd-4883a7851353.jpeg)

## まとめ
業務での開発と違い好き放題設定できるので楽しいですね😜
次の記事では、Dockerで動くようにしてみようと思います。

今回開発中のリポジトリはこちらです。

https://github.com/takahiro-okada/nextjs-jocv