Next.jsプロジェクトに追加したい設定11個

# はじめに

[create-next-app](https://nextjs.org/docs/pages/api-reference/create-next-app)を使うと、Next.jsに必要なパッケージの導入や設定が完了した状態になり、複雑な作業をせずにプロジェクトを開始できます。
しかし私は、いつももう少し追加設定を行っています。本日はその内容を紹介いたします。

なお、割と万人に納得してもらえそうなものもあれば、かなり個人の好みのものもあります。

## 当記事の前提バージョン

| ソフトウェア                                                                                                            | バージョン |
| ----------------------------------------------------------------------------------------------------------------------- | ---------- |
| [Next.js](https://nextjs.org/)                                                                                          | 14.0.3     |
| [pnpm](https://pnpm.io/)                                                                                                | 8.11.0     |
| [Visual Studio Code](https://code.visualstudio.com/)                                                                    | 1.84.2     |
| [Node.js](https://nodejs.org/en)                                                                                        | 20.10.0    |
| [Prettier](https://prettier.io/)                                                                                        | 3.1.0      |
| [Prettier Formatter for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) | 10.1.0     |
| [Secretlint](https://github.com/secretlint/secretlint)                                                                  | 8.0.0      |
| [ESLint](https://eslint.org/)                                                                                           | 8.55.0     |
| [typescript-eslint](https://typescript-eslint.io/)                                                                      | 6.13.2     |
| [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier)                                            | 9.1.0      |
| [eslint-plugin-redos](https://www.npmjs.com/package/eslint-plugin-redos)                                                | 4.4.5      |
| [eslint-plugin-simple-import-sort](https://github.com/lydell/eslint-plugin-simple-import-sort)                          | 10.0.0     |
| [TypeScript](https://www.typescriptlang.org/)                                                                           | 5.3.2      |
| [better-typescript-lib](https://github.com/uhyo/better-typescript-lib)                                                  | 2.5.0      |
| [npm-run-all2](https://github.com/bcomnes/npm-run-all2)                                                                 | 6.1.1      |


### pnpmについて

私は普段、パッケージマネージャーにnpmではなく[pnpm](https://pnpm.io/)を使っています。npmよりパッケージインストールが高速であったり、ちょっと良い機能が付いていたりします。[^bun]
この記事の内容のほとんどはnpmとpnpmのどちらでも問題ないように書いているつもりですが、念のため前提として紹介させていただきます。

[^bun]: 最近は[Bun](https://bun.sh/)もパッケージマネージャーとして有力ですが、ロックファイルがバイナリーファイルであることが嫌で使っていません。

# create-next-appの実行(オプション追加)

`create-next-app`にはいくつかオプションがあります。私はいつも以下のようにしています。

```shell:
# pnpmの場合
pnpm dlx create-next-app ./some-directory --ts --no-tailwind \
      --eslint --app --src-dir --import-alias '@/*'
# npmの場合
npx create-next-app ./some-directory --ts --no-tailwind \
      --eslint --app --src-dir --import-alias '@/*'
```

なお、`create-next-app`にオプションを何も渡さないで実行すると、以下のような質問を聞かれます。私は毎回回答するのが面倒なので、先にオプションを指定しています。

```
What is your project named?  my-app
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
```

ここでは、この記事の前提になっていたり、重要なオプションについてのみ紹介します。他で気になるものがあれば[create-next-appのマニュアルの該当箇所](https://nextjs.org/docs/app/api-reference/create-next-app#non-interactive)をご覧ください。

## --ts

Next.jsのTypeScript統合を有効にします。TypeScriptによる型の恩恵は積極的に受けたいところです。

## --eslint

Next.jsの[ESLint](https://eslint.org/)統合を有効にします。ESLintはJavaScriptのLinterのデファクトスタンダードです。有効にすると、`pnpm lint`コマンドでチェックできるようになります。ルールはNext.jsのデフォルトがあらかじめ適用されており、[eslint-plugin-next](https://www.npmjs.com/package/@next/eslint-plugin-next)や[eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react)なども有効になります。
なおこの記事では後の説明でこのESLintの設定を強化しています。

# 追加設定の紹介

ここから、`create-next-app`実行後に行う推奨設定をご紹介していきます。  
基本的に推奨度順にご紹介していますが、設定の前後関係も考えて入れ替えています。
推奨度はメリット・デメリットの大きさを総合的に(主観で)判断しています。

## 1. パッケージのバージョン固定 (推奨度:3)

- 推奨度：★★★☆☆
- メリット: プロジェクト内で依存パッケージの状態が統一される
- デメリット: 依存パッケージ更新の手間が増える・依存パッケージが古いまま放置されやすい

`create-next-app`を実行して作成された`package.json`では以下のように、Next.js関係以外の依存パッケージのバージョンが固定されていない状態になっています。

```json:package.json抜粋
  "dependencies": {
    "react": "^18",
    "react-dom": "^18",
    "next": "14.0.3"
  },
  "devDependencies": {
    "typescript": "^5",
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "eslint": "^8",
    "eslint-config-next": "14.0.3"
  }
```

しかし、プロジェクト内でバージョン違いによるトラブルを避けるため、`package.json`の段階でバージョンを固定したいところです。まず、プロジェクトルートに以下のファイルを置き、今後インストールするパッケージのバージョンを固定します。

```:.npmrc
save-exact = true
```

そして、既に`package.json`に記載されたパッケージは全ていったんアンインストールしてから再度インストールすることで、バージョンが固定されます。

<details><summary>結果としてpackage.jsonはこのようになります</summary><div>

```json:package.json抜粋
  "dependencies": {
    "next": "14.0.3",
    "react": "18.2.0",
    "react-dom": "18.2.0"
  },
  "devDependencies": {
    "@types/node": "20.10.3",
    "@types/react": "18.2.42",
    "@types/react-dom": "18.2.17",
    "eslint": "8.55.0",
    "eslint-config-next": "14.0.3",
    "typescript": "5.3.2"
  }
```

</div></details>

## 2. 秘匿情報チェック(Secretlint) (推奨度:5)

- 推奨度: ★★★★★
- メリット: 秘匿情報の漏洩が起きにくくなる
- デメリット: 特になし

ソースコードや設定ファイルに各種アクセスキーなどを記述したままGitHubに公開してしまった、というようなトラブルは後を絶ちません。これを防ぐツール[Secretlint](https://github.com/secretlint/secretlint)を導入します。

導入は簡単で、本体とルールセットのパッケージをインストールし、設定ファイルを作成するだけです。

```shell
# pnpmの場合
pnpm add --save-dev secretlint @secretlint/secretlint-rule-preset-recommend
pnpm secretlint --init
# npmの場合
npm install --save-dev secretlint @secretlint/secretlint-rule-preset-recommend
npx secretlint --init
```

そして、package.jsonのスクリプトに登録しましょう。

```diff_json:package.json抜粋
 "scripts": {
   "dev": "next dev",
   "build": "next build",
   "start": "next start",
   "lint": "next lint",
+  "secretlint": "secretlint --maskSecrets --secretlintignore .gitignore '**/*'",
```

例えば、GitHubのトークンを「とりあえず」とソースコードに書いてしまったとします

```javascript: tmp-secret.mjs
export const GH_TOKEN = "ghp_AAAAA2AAAAaAaAaaAAaaaAaaaAAaAAa2AAaAA";
```

この状態でSecretlintを実行すると、エラーが発生し、どのファイルのどの行にシークレットが存在するか表示してくれます。

```shell: Secretlint実行結果
$ pnpm secretlint

> nextjs-secretlint-demo@0.1.0 secretlint /workspaces/dev/nextjs-secretlint-demo
> secretlint --maskSecrets --secretlintignore .gitignore '**/*'


/workspaces/dev/nextjs-secretlint-demo/tmp-secret.mjs
  1:25  error  [GITHUB_TOKEN] found GitHub Token(*****************************): ****************************************  @secretlint/secretlint-rule-preset-recommend > @secretlint/secretlint-rule-github

✖ 1 problem (1 error, 0 warnings)

 ELIFECYCLE  Command failed with exit code 1.
```
なお、CIツールで実行してログが残ることも考えて、シークレットの具体値をマスクするよう`--maskSecrets`オプションを付与しています。

## 3. フォーマッタ追加(Prettier) (推奨度:5)

- 推奨度: ★★★★★
- メリット: プロジェクト内でコーディングスタイルが統一される
- デメリット: 特になし

多くのプログラミング言語では、空白や改行を入れる・入れないなど、見た目・コーディングスタイル(フォーマット)に自由度があります。しかし、プロジェクト内ではルールを決めて統一するべきです。そしてそのルールは、各開発者が頑張って守るよりも、仕組みで担保できるとより良いです。  
しかし、Next.jsやcreate-next-appでは、特にフォーマッタが設定されていないようなので、ここで[Prettier](https://prettier.io/)というJavaScript界隈でデファクトスタンダード[^Biome]なフォーマッタを導入します。

[^Biome]: 最近は[Biome](https://biomejs.dev/)がPrettierに代わるフォーマッタとして話題です。

### Prettierをインストール

```shell:
# pnpmの場合
pnpm add --save-dev prettier
# npmの場合
npm install --save-dev prettier
```

### Prettierを設定(オプション)

Prettierは一定のスタイルがデフォルト設定されており、通常変える必要はありません。セミコロンなしにしたい、文字列はシングルクォートにしたい、など変えたい場合は、設定ファイルをプロジェクトのルートに置きます。詳しくは[Prettierの公式ドキュメント](https://prettier.io/docs/en/options)などをご覧ください。
参考までに、私は以下のような設定をしています。

<details><summary>prettier.config.mjs</summary><div>

```javascript:prettier.config.mjs
/** @type {import("prettier").Config} */
const config = {
    tabWidth: 4,
    printWidth: 120,
    overrides: [
        {
            files: "*.{json,json5,html,yaml,yml}",
            options: {
                tabWidth: 2,
            },
        },
        {
            files: "*.md",
            options: {
                tabWidth: 2,
                trailingComma: "none",
            },
        },
    ],
};

export default config;
```

</div></details>

### .prettierignoreの設定

Prettierは`.gitignore`で指定したファイルをフォーマットから除外しますが、それ以外にも除外したいファイルがある場合は`.prettierignore`ファイルを設定します。
npmやpnpmのロックファイルはGit管理しますが、中身をnpmやpnpm以外でいじるべきではないため、設定します。

```:.prettierignore
/pnpm-lock.yaml
/package-lock.json
```

### npm scriptsを設定

ここまでで、Prettierのフォーマットチェックは、

```shell:
# pnpmの場合
pnpm prettier --cache --check .
# npmの場合
npx prettier --cache --check .
```

フォーマット自動修正は、

```shell:
# pnpmの場合
pnpm prettier --cache --write .
# npmの場合
npx prettier --cache --write .
```

のように実行できますが、`package.json`の`scripts`に定義してしまう方が良いでしょう。

```diff_json:package.json
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
+   "prettier-check": "prettier --cache --check .",
+   "prettier-fix": "prettier --cache --write .",
```

これで、以下のように実行できます。

```shell:
# pnpmの場合
pnpm prettier-check
pnpm prettier-fix
# npmの場合
npm run prettier-check
npm run prettier-fix
```

:::note info
`--cache`オプションは、Prettierの実行結果をキャッシュし、変更がないファイルの再チェックをスキップすることで高速化します。Prettierは大規模プロジェクトになると遅く感じることもあるため、このオプションを追加しています。
:::

### ファイル保存時に自動的にフォーマットする設定

毎回必要なときにコマンドを実行するのでは、まだいまいちです。
エディタでファイルを保存するたびに自動でフォーマットしてしまいましょう。

VSCodeに、[Prettierプラグイン](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)を導入します。次に、VSCodeのデフォルトフォーマッタをPrettierにし、保存時にフォーマットする設定します。例えば、以下のように設定します。

```json:settings.json抜粋
 "editor.formatOnSave": true,
 "[typescript]": {
   "editor.defaultFormatter": "esbenp.prettier-vscode"
 },
 "[typescriptreact]": {
   "editor.defaultFormatter": "esbenp.prettier-vscode"
 },
 "[javascript]": {
   "editor.defaultFormatter": "esbenp.prettier-vscode"
 },
 "[json]": {
   "editor.defaultFormatter": "esbenp.prettier-vscode"
 },
```

WebStormなどIntelliJ系IDEには、Prettier用プラグインがあるようです。参考：[マニュアル](https://www.jetbrains.com/help/webstorm/prettier.html)

## 4. ESLint強化 (推奨度:4)

- 推奨度: ★★★★☆
- メリット: コード品質の向上・脆弱性の回避につながる
- デメリット: エラーへの対処に時間がかかり生産性が下がる可能性がある

[create-next-appのオプション](#create-next-appの実行オプション追加)で説明したとおり、Next.jsにはESLint統合機能が含まれます。これだけでもかなり有用ですが、さらに強化したいところがあります。以下のプラグインや設定セットを導入します。

| 種類       | 名前                                                                                           | 目的                                                                                                                                                                                                                     |
| ---------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| プラグイン | [eslint-plugin-simple-import-sort](https://github.com/lydell/eslint-plugin-simple-import-sort) | import文の自動ソートを行う。あえて設定オプションをほとんど設けずシンプルにしてあり、分かりやすい。[^eslintsort]                                                                                                          |
| プラグイン | [typescript-eslint](https://typescript-eslint.io/)                                             | ESLintのTypeScript用ルールを提供する。例えば[配列にfor-in文を使うとエラー](https://typescript-eslint.io/rules/no-for-in-array/)にしてくれるようになる。                                                                  |
| プラグイン | [eslint-plugin-redos](https://www.npmjs.com/package/eslint-plugin-redos)                       | 正規表現に[ReDoS(正規表現に関するDos攻撃)脆弱性](https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS)がないかをチェックする。例えば`/\s+$/`のような正規表現を書くとエラーとしてくれる。 |
| 設定セット | [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier)                   | Prettierが担当するフォーマットに関するルールをESLint側で無効化する。ここまででフォーマットに関するルールはESLintに設定されていないはずだが、念のため導入する。                                                           |

[^eslintsort]: ESLint内蔵ルールの[sort-imports](https://eslint.org/docs/rules/sort-imports)でもある程度できますが、パッケージ名やパス名でのソートに対応していないなど、機能不足です。ただ、import文の順序を入れ替えることはコードの見た目にとどまらず意味を変えることであるため、あえて実装していないという考え方のようにも見えます。

```shell:pnpmの場合
pnpm add --save-dev eslint-config-prettier eslint-plugin-simple-import-sort \
     @typescript-eslint/parser @typescript-eslint/eslint-plugin \
     eslint-plugin-redos
```

```shell:npmの場合
$ npm install --save-dev eslint-config-prettier eslint-plugin-simple-import-sort \
      @typescript-eslint/parser @typescript-eslint/eslint-plugin \
      eslint-plugin-redos
```

そして以下のように、プロジェクトルートの`.eslintrc.json`ファイルを記述します。  
Next.jsが設定する`next/core-web-vitals`設定を生かしつつ、先述した設定を追加しています。

```json:.eslintrc.json
{
  "extends": [
    "next/core-web-vitals",
    "eslint:recommended",
    "plugin:@typescript-eslint/strict-type-checked",
    "prettier"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": true
  },
  "plugins": ["simple-import-sort", "@typescript-eslint", "redos"],
  "rules": {
    "simple-import-sort/imports": "error",
    "simple-import-sort/exports": "error",
    "@typescript-eslint/no-misused-promises": [
      "error",
      {
        "checksVoidReturn": false
      }
    ],
    "redos/no-vulnerable": "error"
  }
}
```

:::note warn
`plugin:@typescript-eslint/strict-type-checked`は"strict"であり、厳しいと感じるかもしれません。その場合は`plugin:@typescript-eslint/recommended-type-checked`にしたほうがよいでしょう。
:::

### 自動修正をスクリプトに追加

ESLintには一部のルールにエラーの自動修正機能が付いていますが、Next.jsではこれが`package.json`のスクリプトに記載されません。Next.jsで有効になるルールでは自動修正に対応したものが無いのかもしれませんが、今回いろいろなルールを追加したので、自動修正もスクリプトに追加しておきましょう。

```diff:package.json
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
+   "lint-fix": "next lint --fix",
```

## 5. package.jsonのスクリプトの整理・並列実行 (推奨度:5)

- 推奨度: ★★★★★
- メリット: ワンコマンドで必要なチェックや修正を実行できる
- デメリット: 強いて言えば、スクリプトが複雑になる

ここまでの手順を実施すると、`package.json`のscriptsは以下のようになっているはずです。

```json:package.json抜粋
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "prettier-check": "prettier --cache --check .",
    "prettier-fix": "prettier --cache --write .",
    "lint-fix": "next lint --fix",
    "secretlint": "secretlint --maskSecrets --secretlintignore .gitignore '**/*'"
  },
```

ツールと実施内容で整理すると以下のとおりです。

| ツール     | チェック       | 自動修正     |
| ---------- | -------------- | ------------ |
| ESLint     | lint           | lint-fix     |
| Prettier   | prettier-check | prettier-fix |
| Secretlint | secretlint     | (なし)       |

これだけの数があると、チェックや自動修正をまとめて実施するスクリプトを用意した方が良いです。

そこで、package.jsonのスクリプトで複数のコマンドを実施するために、[`npm-run-all2`](https://github.com/bcomnes/npm-run-all2)[^npmrunall]というパッケージを導入します。

[^npmrunall]: これまで[npm-run-all](https://github.com/mysticatea/npm-run-all)というツールを使っていたのですが、致命的なバグがあるため、forkしたnpm-run-all2というパッケージを使うとよい、とこの記事を書いている最中に知りました。参考：[そのテスト、最後まで実行されていますか？　jestとnpm-run-allの恐るべき罠](https://zenn.dev/babel/articles/jest-npm-run-all-for-babel)

```shell:
# pnpmの場合
pnpm add --save-dev npm-run-all2
# npmの場合
npm install --save-dev npm-run-all2
```

このパッケージは、`run-p`というコマンドで複数のスクリプトの並列実行、`run-s`というコマンドで複数のスクリプトの順次実行を行えます。
scriptsは以下のように書き換えます。

```json:package.json抜粋
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "run-p --continue-on-error --print-label lint:*",
    "lint:eslint": "next lint",
    "lint:prettier": "prettier --cache --check .",
    "lint:secretlint": "secretlint --maskSecrets --secretlintignore .gitignore '**/*'",
    "fix": "run-s --continue-on-error fix:*",
    "fix:eslint": "next lint --fix",
    "fix:prettier": "prettier --cache --write ."
  },
```

チェックは"lint:(ツール名)"、自動修正は"fix:(ツール名)"という名前で整理しました。
そして"lint:"で始まるものを並列実行するコマンドを`lint`に登録します。
また"fix:"で始まるものを順番に実行するコマンドを`fix`に登録します。

## 6. CIツールによるチェック(推奨度:5)

- 推奨度: ★★★★★
- メリット: ソースコードの問題をすぐに発見・共有することができる
- デメリット: 運用に手間やコストがかかる(場合もある)

CI(継続的インテグレーション)の重要性はこの記事で述べるまでもないことだと思います。
せっかくチェックツールによる各種チェックを整備したので、これは開発者の手元だけでなく、GitHub Actions、CircleCI、JenkinsなどCIツールで随時チェックするようにします。また、Next.jsのビルドがエラーを吐かないかも一緒にチェックした方が良いでしょう。
GitHub Actionsであれば、以下のようなワークフローになります。

<details><summary>.github/workflows/action.yaml</summary><div>

pnpm前提です。npmの場合は適宜変更してください。

```yaml:.github/workflows/action.yaml
name: Build and Lint

on:
  workflow_dispatch:
  pull_request:
  push:

jobs:
  build-lint:
    name: Build and Lint

    runs-on: ubuntu-22.04

    steps:
      - name: Checkout the source
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
        with:
          show-progress: false
          submodules: recursive

      - name: Setup pnpm
        uses: pnpm/action-setup@d882d12c64e032187b2edb46d3a0d003b7a43598 # v2.4.0
        with:
          standalone: false

      - name: Setup Node.js
        uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
        with:
          node-version-file: .nvmrc
          cache: pnpm

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - run: pnpm build

      - run: pnpm lint
```

</div></details>

## 7. 依存パッケージ更新チェック自動化(Renovate/Dependabot) (推奨度:3)

- 推奨度: ★★★☆☆
- メリット: 依存パッケージの更新の手間が減る・古いまま放置されない
- デメリット: それなりに運用に手間・コストがかかる

[1. パッケージのバージョン固定 (推奨度:3)](<#1-パッケージのバージョン固定-推奨度3>) にて、パッケージはパッチレベルまでバージョンを固定しました。これによりプロジェクト内でバージョン違いによるトラブルが発生しなくなる反面、パッケージのバージョンアップは自動でされなくなるため、自動アップデートツールの導入をお勧めします。
GitHubであれば、RenovateやDependabotが良いでしょう。これらを導入すると、GitHubであればバージョンアップのプルリクエストを自動で作成してくれたりします。
導入手順はこれまでのようなコマンドラインや設定ファイルだけではなくGitHub側の設定も必要で複雑なため、申し訳ありませんが以下のような記事を参考にしてください。

[GitHubにDependabotを導入して依存ライブラリを自動アップデートする | DevelopersIO](https://dev.classmethod.jp/articles/github-dependabot-2021/)
[Renovate を使ってほぼ完全自動で依存パッケージをアップデートする｜Tomachi ](https://zenn.dev/book000/articles/renovate-dep-auto-update)

ただ、うまく設定・運用しないと、大量のパッケージ更新のプルリクエストが残って邪魔だったり、頻繁なプルリクエスト作成によりCIツールに負担(コスト)をかけたりします。

## 8. Node.jsのバージョン固定 (推奨度:3)

- 推奨度: ★★★☆☆
- メリット: プロジェクト内でNode.jsのバージョンが統一される
- デメリット: 
  - バージョンを厳密に指定した場合: バージョン更新の手間が増える・古いまま放置されやすい
  - メジャーバージョンのみの場合: 特になし

ライブラリや実行プログラムを作成し、[npm](https://www.npmjs.com/)などで公開する場合、幅広いNode.jsバージョンで動くようにするほうが良いでしょう。しかし、Webアプリケーションを作る場合、それが動くNode.jsバージョンは自分たちの都合で一個に決めることができます。
そしてそのバージョンはメンバーに周知するだけでなく、設定ファイルで明示しましょう。

私はNode.jsのバージョン管理に[nvm](https://github.com/nvm-sh/nvm)を使っているため、`.nvmrc`ファイルにバージョンを記述します。

```:.nvmrc
20.10.0
```

細かいバージョンまで指定すると、更新の手間が増えることは否めません。その場合でも、少なくともメジャーバージョンは指定しましょう。

```:.nvmrc
20
```

nvmの他、[Volta](https://volta.sh/)なども有力なツールだと思います。重要なのは、各プロジェクトにてバージョン管理方法を決め、設定ファイルでバージョンを明記することです。

### Vercelの場合

Vercelにデプロイする場合は、`package.json`の`engines`内で設定すると、そのメジャーバージョンが使われ、マイナーバージョン以下は無視されるようです。

```json:package.json
	"engines": {
		"node": "^18.0.0"
	}
```

## 9. TypeScriptの設定変更(推奨度:3)

- 推奨度: ★★★☆☆
- メリット: ECMAScript最新機能が使える・型チェック強化により品質が上がる
- デメリット: エラーへの対処に時間がかかり生産性が下がる可能性がある

TypeScriptの設定はcreate-next-appが生成した状態そのままで大きな問題はありませんが、`target`が`es5`に設定される問題があります。この状態だとTop Level Awaitや[クラスのプライベートプロパティ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes/Private_properties)が使えないなどの問題があるため、`esnext`に変更します。
これはどうも、Next.js本体では修正されたものの、create-next-appの修正が漏れたもののようです。参考：[Remove unused target: es5 from tsconfig.json](https://github.com/vercel/next.js/pull/44567)

またTypeScriptの型チェックを強化する目的で、いくつかの設定を追加します。
結果として、以下のように変更します。

```diff_json:tsconfig.json抜粋
    "compilerOptions": {
-    "target": "es5",
+    "target": "esnext",
     "lib": ["dom", "dom.iterable", "esnext"],
     "allowJs": true,
     "skipLibCheck": true,
     "strict": true,
+    "noImplicitOverride": true,
+    "noImplicitReturns": true,
+    "noUncheckedIndexedAccess": true,
+    "exactOptionalPropertyTypes": true,
     "noEmit": true,
```

## 10. TypeScriptの型を強化する(better-typescript-lib) (推奨度:2)

- 推奨度: ★★☆☆☆
- メリット: より型安全なコーディングができ、品質が上がる
- デメリット: 
  - (pnpmの場合) 設定が複雑になる
  - 型システムの重要な部分を該当ライブラリ作者に依存する

TypeScriptはTypeScriptで作られたライブラリだけでなく、JavaScriptのライブラリについても型定義ファイルを用意することで、TypeScript上で型の恩恵を受けることができます。
[JavaScriptの標準オブジェクト](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference#%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88)については、TypeScriptが型定義ファイルを提供してくれています。
しかし、この型定義ファイルにはいまいちなところがあります。例えば`JSON.parse`メソッドは`any`を返しますが、なぜ`unknown`ではないのでしょうか。
これは、`unknown`型はTypeScriptにおいて比較的最近導入されたものであり、それ以前との互換性のために改善出来ないという事情があるようです。

そこで、`better-typescript-lib`というライブラリを導入します。ライブラリの詳細は、作者が[紹介記事](https://zenn.dev/uhyo/articles/better-typescript-lib-v2)を書いていますので、お読みください。

導入は、pnpmの場合は事前に`.npmrc`に次のように設定を入れます

```:.npmrc
public-hoist-pattern[]=@typescript/*
```

そしてパッケージを追加するだけで、それ以上の設定は不要です。

```shell:
# pnpmの場合
pnpm add --save-dev better-typescript-lib
# npmの場合
npm install --save-dev better-typescript-lib
```

## 11. gitの自動改行コード変更機能を無効にする (推奨度:1)

- 推奨度: ★☆☆☆☆
- メリット: Windowsでの改行コードの混乱が防止されるかもしれない
- デメリット: 特になし? (あまり一般的ではない設定をいれることの是非)

gitは[`core.autocrlf`](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%81%AE%E8%A8%AD%E5%AE%9A#_core_autocrlf)という設定で改行コードを`CRLF`と変換してくれる機能があります。私は個人的にこの機能はお節介であり余計な混乱を生むと考えます。また実はさきほど導入したPrettierは、デフォルトで`LF`に統一してくれます。改行コードはフォーマットの一部ということですね。
よって、gitの改行コード関連機能を強制的に無効化します。

```:.gitattributes
* -text
```

[`text`](https://git-scm.com/docs/gitattributes#_text)という属性は、gitで改行コード変換機能を有効にするものです。`* -text`は全てのファイルで改行コード変換機能を無効にします。

<details><summary>gitの改行コード変換機能が不要な理由</summary><div>

この機能は2023年に必要でしょうか。Windowsのメモ帳も今は`LF`改行コードを認識するくらいで、Windowsなら`CRLF`というのは時代遅れの考え方です。少なくともWindows上でNext.js開発に使うエディタやIDEが`LF`に対応していないことはあり得ません。
そして、この設定は各開発者個人ごとのgit設定であり、プロジェクト内で統一(強制)できません。gitリポジトリを介して操作をする分には統一されていなくても問題なさそうですが、git外でファイルを共有したりすると混乱が生じます。git操作が苦手な人が、ファイルをチャットに添付したりすると…
またこの設定は`CRLF`でコミットすると自動的に`LF`に変換してコミットする機能も兼ねています。これは少し有用ですが、やはりプロジェクト内で統一設定ができない問題があるため、頼りにできません。一部の開発者で設定が漏れて、`CRLF`がコミットされる恐れが残ります。

</div></details>

# 設定ツールを作った

ここまでの設定を手で行うのはそれなりに大変だしミスもするかもしれません。そこで、設定を自動で行うツールを自分用に作って使っています。

https://github.com/tksst/next-app-additions

`create-next-app`実行後、プロジェクトフォルダで以下のコマンドを実行すると、全てを設定してくれます。

```shell:
pnpm dlx @tksst/next-app-additions
```

:::note warn
pnpm前提であり、npm向けに作ったプロジェクトには対応していません。
:::

# 設定しなかったこと

## gitコミット時に自動チェック(husky/lint-staged)

[husky](https://github.com/typicode/husky)と[lint-staged](https://github.com/lint-staged/lint-staged)を使って、gitのコミット時にフックでlintチェックを行い、失敗した場合はコミットできないようにする手法をよく見かけます。が、私はなんとなく気が向かないため、やっていません。最終的にCIでチェックして品質を担保しているのも理由の一つです。
ただ、秘匿情報公開は結果が重大なのと、CIでのチェックでは手遅れになるケースも多いので、Secretlintだけはやった方がいいのかも、という気もします。

## テスト関連

私はNext.jsでのテスト関連に明るくないため、今回触れていません。Next.jsのマニュアルでテストツールの紹介がされているので、参考にしてください。
[Next.js 公式ドキュメント - Optimizing - Testing ](https://nextjs.org/docs/app/building-your-application/testing)
[上記の非公式日本語訳(残念ながら結構古い)](https://nextjs-ja-translation-docs.vercel.app/docs/testing)

# まとめ

ここまで、様々な設定を紹介してきました。ご紹介したものをそのまま、あるいはプロジェクト事情や個人の好みに合わせて、ぜひ採用してみてください。

なお、取り上げた設定は、概ね、以下を意識しています。

- セキュリティ(Secretlint)
- プロジェクト内標準化
  - プロジェクトのルールを作り、仕組みで担保する(Prettier, ESLinter, CI)
  - タイミングによって状態が変わらないようにする(バージョン固定系)
- 開発者体験(DX)の強化(TypeScript/ESLint/パッケージ更新チェック)

ここで紹介した個別の内容以外にも、上記を意識したプロジェクト整備を心がけると良いのではないでしょうか。

# 最後に

ここまでたくさん設定を紹介しましたが一方で、プロジェクトに設定を追加(作り込み)すればそれだけNext.jsデフォルト状態から複雑になっていくことは間違いありません。それに見合うメリットがあるのか、は悩ましいところです。
これはいわゆる「[奥が深い症候群](http://0xcc.net/misc/bad-knowhow.html)」なのではないか? とも思います。なので、できることならNext.js(create-next-app)がこういった内容を取り込んで「隠蔽」してくれると嬉しいなと思います。