LintとTestをフル活用したNext.jsのテンプレ作成ガイド

# 1...2の...ポカン!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/9b056a42-ce45-31be-1a3a-86d4a93d9da8.png)


私は**個人開発で小さなアプリを何度もこさえることがあり**ますが、
その度に必要なパッケージをインストールしたり、設定ファイルを書くのは面倒です。

しかも、私の脳は**１つ新しいことを学ぶと１つ前のものは忘れる**という仕様なので、
その都度調べるということが起きてしまいます。

**私の脳みそを改造できたらいい**のですが、
そんなことできるは**ショッカー**か**ダイジョーブ博士**ぐらいです。

なので代替案として**テンプレを作っておいて、いつでもそれを使えるようにしておこう！**
という目論見で開かれたのがこの会です。

**参加者は私一人です。**
それではいきましょう。

# Nextにパッケージ何入れようかサミット

**厳重な審査の結果、今回の雛形に選ばれたのは以下のパッケージです。**
後の章でこれらの説明や、導入方法について記述します。
また、これら以外にもいくつかの細かいパッケージも必要になってきますが、ここでの記載は省きます。

|パッケージ名|説明|備考|
|---|---|---|
|Typescript|みんな大好きTypescript||
|ESLint|js/tsのファイルの書き方を監督してくれる人|リント用|
|Prettier|コードを綺麗にしてくれる人|整形用|
|StyleLint|スタイルの書き方を監督してくれる人|リント用|
|CommitLint|commit messageの書き方に口出ししてくる人|リント用|
|Sass|cssをsass形式で描けるようにしてくれる人||
|MaterialUI|コンポーネントの詰め合わせパックの人||
|DependBot|パッケージのバージョンを新しくしてくれる人||
|Jest|js/tsのテストをできるようにしてくれる人|テスト用|
|StoryBook|見た目のテストとかカタログ（jsDoc見た目版みたいな）を作る人|テスト用|

## 惜しくも今回含まれなかった方々
`Redux`や`Recoil`、`ApploClient`とかの**「データをメモリ保存する勢」**や
`firebase`とか`axios`とかの**「非同期通信を簡単に実装します勢」**も含めませんでした。

`自分でサーバーを実装するか？` `GraphQLを使うのか？` `RESTだけでいくのか？`などの要因によって何をいれたいかは変わってくるので、ここら辺は雛形にいれなくてもいいかなと思ったからです。

また、`tailwindcss`や`styled component`も含めませんでした。
個人的に`CSS module`が好きなので、そちらを採用したいという結論がサミットでは出たためです。

## ディレクトリ構成について

今回は`Atomicデザイン`を採用します。
この構成について賛否両論ありますが、詳しい議論について私はあまり知らないので**脳死でAtomic**にしました。
ディレクトリはこんな感じにしています。

```
src
├── pages
│   ├── _app.tsx
│   ├── api
│   └── index.tsx
├── components
│   └── atoms
│   └── molecules
│   └── organisms
│   └── templates
└── styles
    ├── Home.module.css
    └── globals.css
```

因みに、**Nextはデフォルトで`src`ディレクトリがない**ので、それを追加する必要があります。
（必要はない。私が追加したいだけ）

## この先読むのが面倒くさい方へ

ここにコードがあるから、これを`clone`して貰えばこのパッケージで開発を進めることができます。

https://github.com/wenwen03/next-standard

`StoryBook`の導入だけ私が試すと`vulnerabilities`が出てしまって直せていないので、
`StoryBook`込みのものは`width_storybook`というブランチに取り分けてあります。

# プロジェクトの作成

では実際にこれらを追加して行きましょう。
**以下のコマンドで`TypeScript`をデフォルトとするNext.jsのプロジェクトを作成します。**
「すでに作成済みのプロジェクトにパッケージを追加したい」という人は飛ばして下さい。

```
npx create-next-app --typescript
```
実行したら`プロジェクトの名前はどうするよ？`って聞かれると思うので、
いい感じの名前をつけておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/bf2dc9b4-4dff-7e61-7e9a-f3b7648c0e43.png)

# srcディレクトリの作成

**プロジェクトが作成できたら、次にディレクトリ構造を整理しておきましょう。**
前述の通り、`Next.js`はデフォルトで`src`ディレクトリが存在しないので作ってあげましょう。

と言っても`src`という名前のディレクトリを作って、その中に`styles`とか`pages`とか入れるだけですね。`components`というディレクトリも作っておくといいでしょう。


ディレクトリ構成についてはこれでOKです。
次にESLintの設定をして行きましょう。

# ESLintの設定

`Next.js`では`ver.11`から**デフォルトで`ESLint`が備えられるようになった**
ので特に**インストールする必要はありません**。

なので、`ESLint`の導入の手順は以下のようになります。

1. ~~`ESLint`のパッケージのインストール~~（インストール済だから不要）
2. `src`ディレクトリ配下もチェックするように設定
3. 行末にセミコロン`;`がないとエラーになるように設定
4. `import`文を**絶対パス**で記述するルールの追加
5. `import`文の記述順を**アルファベット順**にする
6. `ESLint`の整形コマンドを登録しておく
7. （おまけ）VScodeのESLint拡張機能を追加する

## `src`ディレクトリ配下もチェックするように設定

`lint`のコマンド実行時に**デフォルトでは`src`ファイルディレクトリ配下は無視されます。**
このままでは**`src`が可哀想なので、仲間に入れてあげましょう。**
`package.json`の`scripts`にある`"lint"`の部分を以下のようにするだけです。

参考：[Basic Features: ESLint | Next.js](https://nextjs.org/docs/basic-features/eslint#linting-custom-directories)

```package.json
  "scripts": {
    ・・・
    // 「--dir src」を追加
    "lint": "next lint --dir src"
  }
```

## 行末にセミコロン`;`がないとエラーになるように設定

行末にセミコロンがなくても動きますが、「必ず全部つける」で統一しておいた方が
綺麗なのでセミコロンが無ければ、ESLintに怒ってもらうように設定します。

[ESLintのルール](https://eslint.org/docs/rules/](https://eslint.org/docs/rules/)

```.eslintrc.json
{
  ・・・
  // 追記
  "rules": {
    // セミコロンない場合、エラー出力
    "semi": ["error", "always"]
  }
}
```

## `import`文を**絶対パス**で記述するルールの追加

**`import`文を記述する時に相対パスじゃなくて絶対パスで書きたいですよね。**

`ESLint`で絶対パスの`import`に制限するルールを追加するには
`.eslintrc.json`に記述するだけでです。

```.eslintrc.json
  "rules": {
    "no-restricted-imports": [
      "error",
      {
        "patterns": ["./", "../"]
      }
    ]
  }
```

ついでに、以下のように絶対パスを`@/...`と書けるように設定しておきましょう。

```typescript
import styles from '../styles/Home.module.css'; // こうじゃなくて
import styles from '@/styles/Home.module.css'; // こう
```

`tsconfig.json`に以下のように記述してあげれば
`@/...`を`src/...`と解釈してくれるようになります。

```tsconfig.json
"compilerOptions": {
    ・・・
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
}
```

## importの順番をアルファベット順にする

些細なことですが、**importの順番もアルファベット順**だったら
気持ちいい気がするので、`ESLint`にお願いしておきましょう。
**`.eslintrc.json`を以下のようにするだけです。**

```.eslintrc.json
{
  "extends": [
    ・・・
    // 追記
    "plugin:import/recommended",
    "plugin:import/warnings"
  ],
  "rules": {
    ・・・
    // import の順番をルール化
    "import/order": [
      "error",
      {
        "alphabetize": {
          "order": "asc"
        }
      }
    ]
  }
}

```

## `ESLint`の整形コマンドを登録しておく

`ESLint`に従ってコードを整形してくれるコマンドを`package.json`に追加しておきましょう。

:::note
commit時に自動でチェック・修正してくれる設定は後述。
その際にここで定義したコマンドを呼ぶようにするので、
ここで登録しておくのがいいかも。
:::

```package.json
  "scripts": {
    ・・・
    // 以下を追加
    "lint:fix": "eslint src --ext .js,jsx,.ts,.tsx --fix"
  }
```

これで**`npm run lint:fix`を実行すれば、綺麗に整形される**ようになっているはずです。


## （おまけ）VScodeのESLint拡張機能を追加する

VSCodeの場合は以下の拡張機能を入れると**リアルタイムでLintが適用**され、
**書き方が規則に則っていない場合には警告やエラーが表示**されるようになります。

![https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/715a516c-9974-823a-21f5-82dea7b39121.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/715a516c-9974-823a-21f5-82dea7b39121.png)

# `Prettier`の設定

**`Prettier`はコードを綺麗に整形してくれる人です。**
同じくESLintも綺麗にする能力に長けていますが、
**`Prettier`先生にしかできない整形**があったりするらしいので、この先生も入れます。

`Prettier`導入の手順は以下の通り。

1. `Prettier`に必要なパッケージをインストール
2. `Prettier`と`ESLint`が共存できるような設定の追加
3. （おまけ） VScodeの`Prettier`の拡張機能を追加
4. （おまけ）`Prettier`拡張機能用の設定を記述


## `Prettier`に必要なパッケージをインストール

さて、**`Prettier`をインストールして行きます。**
因みにESLintとPrettierは基本仲良しですが、お互いのこだわりが異なる部分では
喧嘩するらしいので、**喧嘩しないように気を遣ってくれる`eslint-config-prettier`も入れておきます。**

```
npm install -D prettier eslint-config-prettier
```

## `Prettier`と`ESLint`が共存できるような設定の追加

`Perttier`と`ESLint`が喧嘩しないように、設定を追加して行きます。
`.eslintrc.json`の`extends`の部分に`prettier`を加えてあげましょう。

```.eslintrc.json
"extends": ["next/core-web-vitals", "prettier"]
```

これだけです。

## （おまけ） VScodeの`Prettier`の拡張機能を追加

VScodeを使っている人は、`Prettier`の拡張機能を導入しておくことで、
保存時に自動的に整形してくれるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/87ce08bd-e4c9-ac5c-b53c-848cbf090ab0.png)


## （おまけ）`Prettier`拡張機能用の設定を記述

VScodeの`Prettier`拡張機能を入れたら、**`package.json`にその設定を書きます。**
`Prettier`における**設定はVSCode上でも設定できます**。
ですが、**チーム開発する場合を考慮して、コードに残しておく**のがいいと思います。

`package.json`が汚くなるのがいやという人は
`.prettierrc`という設定ファイルを別途書いてもいいです。

```package.json
・・・
  "prettier": {
    "trailingComma": "all",
    "tabWidth": 2,
    "semi": true,
    "singleQuote": true,
    "jsxSingleQuote": true,
    "printWidth": 100
  }
```

上記コードの**各プロパティの説明**

| プロパティ名 | 説明 |
|:-:|:-:|
|trailingComma|末尾のカンマあり|
|tabWidth|tabの長さを定義|
|semi|セミコロンの有無|
|singleQuote|シングルクォーテーションに統一するか|
|jsxSingleQuote|jsx もシングルクォーテーションに統一するか|
|printWidth|1行の最大文字数|

`Prettier`の設定はここまでです！
お疲れ様です！

# Stylelintのインストール

**`Stylelint`とは、スタイル（css, scss, sass）の書き方をチェックし、整形してくれる人です。**
`Stylelint`を導入するステップは以下の通りです。

1. `Stylelint`の必要パッケージをインストール
2. `Stylelint`の設定ファイルを記述する
3. `Stylelint`のチェックコマンド・修正コマンドを追加する
4. （おまけ）VScodeの拡張機能を追加する

## `Stylelint`のインストール

以下の３つをインストールします。

|パッケージ名|説明|
|---|---|
|Stylelint|スタイルファイルの構文解析エンジン|
|stylelint-config-standard|Google's CSS Style Guide や Airbnb's Styleguide などを含むスタイルガイドラインのルール|
|stylelint-order|CSS プロパティをアルファベット順に並べるためのルール|

コマンドは以下の通り。

```
npm install -D stylelint stylelint-config-standard stylelint-order
```

## `Stylelint`の設定ファイルを記述する

次に`.stylelintrc.json`という名前でファイルを作成しましょう。
このファイルに以下の設定を記述します。

```.stylelintrc.json
{
  "plugins": ["stylelint-order"],
  "extends": ["stylelint-config-standard"],
  "rules": {
    "at-rule-no-unknown": [
      true,
      {
        "ignoreAtRules": ["tailwind", "apply", "variants", "responsive", "screen"]
      }
    ],
    "string-quotes": "single",
    "order/properties-alphabetical-order": true
  },
  "ignoreFiles": ["**/node_modules/**"]
}
```

- `plugin`: 使用したい`stylelint-order`のような外部パッケージを記述する場所
- `extends`: 使用したいルールのパッケージを記述する場所
- `rules`: lintのルールを記述する場所
    - `at-rule-no-unknown`: 使用を許可する「標準的ではない[@-規則](https://developer.mozilla.org/ja/docs/Web/CSS/At-rule)」を記述する場所
    - `string-quotes`: 統一したいクォーテーションの種類を記述する場所
    - `order/properties-alphabetical-order`: CSSプロパティをアルファベット順に並べる
- `ignoreFiles`: lintチェックの対象外とするファイルを記述する場所

## `Stylelint`のチェックコマンド・修正コマンドを追加する

**`StyleLint`は`ESLinnt`同様、コマンドを打たないとチェックや修正はしてくれないので、**
あらかじめ、`package.json`にそのコマンドを登録しておきましょう。

:::note
commit時に自動でチェック・修正してくれる設定は後述。
その際にここで定義したコマンドを呼ぶようにするので、
ここで登録しておくのがいいかも。
:::

以下のコマンドを追加しておきましょう。
これで**`npm run lint:style`でチェックし**、
**`npm run lint:style:fix`で整形**することができるようになります。

```pakage.json
  "scripts": {
    ...,
    "lint:style": "stylelint '**/*.{css,scss,sass}'",
    "lint:style:fix": "stylelint --fix '**/*.{css,scss,sass}'"
  }
```

## （おまけ）VScodeの拡張機能を追加する

`Stylelint`という拡張機能を追加します。
これでリアルタイムに`Styelint`に違反している箇所を炙り出すことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/4046250c-b8fd-04f0-6745-89d785cbb817.png)

これで`Stylelint`の導入は完了です！
お疲れ様です！

# `git commit`時に自動で`ESLint`と`StyleLint`をチェックする

これまで、`ESLint`や`StyleLint`を導入して**コマンドを実行すれば、**
**チェックや整形ができる**ようにしてきました。

ここでは、`git commit`した時に自動でLintの整形・チェックを行なってくれるようにします。
**その手順は以下の通りです。**

1. `lint-stage`と`husky`をインストールする。
2. `git commit`時に実行したいコマンドを登録する。
3. huskyに2で登録したコマンドを呼び出すように設定

## `lint-stage`と`husky`をインストールする

ここでは、`git commit`された時を検知し、指定したコマンドを実行してくれる
便利なパッケージ達である`husky`と`lint-stage`をインストールしておきます。

|パッケージ名|説明|
|:-:|:-:|
|lint-stage|stageされたファイルだけをチェックする|
|husky|commitを検知して特定のコマンドを実行させる|

インストールコマンドは以下の通りです。

```
npm install -D husky lint-stage
```

## `git commit`時に実行したいコマンドを登録する

`git commit`したら
1. **ESLint/StyleLintでコードを整形する**
2. **整形した上で、各Lintに引っかかる構文がないか？をチェック**

の２つが実行されるようにして行きたいと思います。
そのために、**`package.json`に以下のコマンドを追加**しましょう。

```package.json
  "scripts": {
    ...,
    "lint": "eslint src --ext .js,jsx,.ts,.tsx",
    "lint:fix": "eslint src --ext .js,jsx,.ts,.tsx --fix",
    "lint:style": "stylelint '**/*.{css,scss,sass}'",
    "lint:style:fix": "stylelint --fix '**/*.{css,scss,sass}'",
    // 以下を追加
    "lint-staged": "lint-staged",
  }
  // 以下を追加
  "lint-staged": {
    "*.{js,ts,jsx,tsx}": [ //（js,ts系のファイルに対して実行するコマンド）
      "npm run lint:fix",
      "npm run lint"
    ],
    "*.{css,scss}": [ //（スタイル系のファイルに対して実行するコマンド）
      "npm run lint:style:fix",
      "npm run lint:style"
    ]
  },
```

## `husky`に上の節で登録したコマンドを呼び出すように設定

続いて、**`git commit`がコールされた時に実行して欲しいコマンドを登録**しておきましょう。
まずは以下のコマンドを実行して下さい。

```
npx husky-init && npm install
```

すると`.husky/pre-commit`というファイルができているはずです。
このファイルに**先ほど作った`lint-stage`というコマンドを実行するように記述**しましょう。

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

npm run lint-staged // ここを追記
```
これで、**`git commit`を入力後すぐにリントの修正・チェックが走る**ようになりました。
お疲れ様です！

# commitlintを導入する
`commitlint`はコミットメッセージをチェックしてくれる方です。

自分の過去のコミットをみると、**コメントが適当すぎでコードを見ないと**
**何しているか不明**なことが多々ある私には必要なパッケージです。

<details><summary>**もう少し`commitlint`について知りたい人へ**</summary><div>
## `commitlint`についてもう少し詳しく
### `commitlint`が許可するメッセージ例
`commitlint`を導入すると、`git commit -m ...`の度に、
「コミットメッセージ」がちゃんとテンプレに沿って書かれているかな？？
と見てくれます。

`commitlint`はデフォルトで以下のようなコミットメッセージだけを通します。

```
title(scope): subject
// 空行
body
// 空行（省略可）
footer（省略可）
```

### `title`, `scope`, `subject`, `body`, `footer`　とは何か？

|param|説明|備考|
|---|---|---|
|title|新機能か？バグ修正か？という情報|決められた値しか受け付けない（後述）|
|scope|影響範囲|影響を受けたファイルやディレクトリなど|
|subject|何をしたのか？を一行でまとめた情報。要約的な。||
|body|なぜ、どのように、という詳しい情報を記述する。|数行で書いてOK|
|footer|チケット番号とか。備考を書くみたい。|なくてもOK|

とりわけ`title`は以下の値しか受け付けないので、注意しましょう。

|param|説明|
|---|---|
|build|ビルド関係|
|ci|CI関係|
|chore|雑事、タイポ修正とか軽微なものなど。|
|docs|ドキュメント更新/追加/修正|
|feat|新機能の追加|
|fix|バグフィックス|
|perf|パフォーマンス|
|refactor|リファクタリング|
|revert|コミット取り消し（git revert）|
|style|コードスタイル|
|test|テスト|

### その他のルール

その他の詳細なルールなどはREADMEを見てもらうのが良さそうです。
自分でルールをカスタムできるみたいなので、お好きにどうぞ。

https://github.com/conventional-changelog/commitlint/#what-is-commitlint

### `commitlint`に関する雑な感想

結構几帳面に見てくれます。**一人で開発していると、ついつい「えいや！」で**
**適当なメッセージを残してしまう**ことがあるのでその抑止力になっていい気がします。

また、デフォルトのルールはAnglarチームの規約に則っているようなので、
**特にこだわりがなければデフォルトのまま使っちゃっていいのかなと思います。**

https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits

</div></details>

***

`commitlint`導入のステップは以下の通りです。

1. `commitlint`に必要なパッケージをインストール
2. `commitlint`の基本設定を記述
3. `commitlint`を実行するコマンドを登録する
4. `commitlint`を`commit`メッセージ入力後に実行させるように設定

## `commitlint`に必要なパッケージをインストール

以下のコマンドで`commitlint`をインストールします。

```
npm install -D @commitlint/{cli,config-conventional}
```

<details><summary>**「`git commit`時に自動で`ESLint`と`StyleLint`をチェックする」を読み飛ばした方へ**</summary><div>

***

`commitlint`単体では、**「`commit`された時に発動する！」という能力が使えない**ので
二人の助っ人も導入しましょう。**`lint-stage`さんと`husky`さんです。**

|パッケージ名|説明|
|:-:|:-:|
|lint-stage|stageされたファイルだけをチェックする|
|husky|commitを検知して特定のコマンドを実行させる|

**以下のコマンドでインストールできます**

```
npm install -D husky lint-stage
```

***

</div></detail>

## `commitlint`の基本設定を記述

**`commitlint`の設定を`package.json`に記述します。**

```package.json
{
  ...,
  "commitlint": {
    "extends": [
      "@commitlint/config-conventional"
    ]
  }
}
```

なお、`package.json`に書きたくない！という人は
`.commitlintrc.json`というファイルを別途作成し、そこに記述してもOKです。

## `commitlint`を実行するコマンドを登録する

`commitlint`を実行するコマンドを`package.json`に定義しておきましょう。

```package.json
"scripts": {
    ...,
    // 追記
    "commitmsg": "commitlint -e $GIT_PARAMS"
  },
```

## `commitlint`を`commit`メッセージ入力後に実行させるように設定

ここまで`commitlint`のインストールと設定を行なってきました。
しかし、**現状`git commit`を実行しても`commitlint`は発動しません。**

**`git commit`でメッセージを入力し終えた時**に、
`commitlint`が実行されるように設定して行きましょう。

<details><summary>**「`git commit`時に自動で`ESLint`と`StyleLint`をチェックする」を読み飛ばした方へ**</summary><div>

***

**「`git commit`時に自動で`ESLint`と`StyleLint`をチェックする」**の章で
記載したコマンドを実行していないとこの先のコマンドを実行しても
上手く動作しないと思うので**以下のコマンドを実行してから先に進んでください**。

```
npx husky-init && npm install
```
***

</div></details>

そのためには先ほどインストールした`husky`を使います。
まずは**以下のコマンドを実行してみましょう。**

```
npx husky add .husky/commit-msg
```

`.husky/commit-msg`というファイルができているはずです。
このファイルは**「commitメッセージを記入後に実行されるコマンドを書くファイル」**です。

**このファイルに`package.json`に登録したコマンドを`記載するだけ**で
**`commit`メッセージ入力後に`commitlint`が実行される**ようになります。

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

npm run commitmsg // ここを追記
```

**これで、`commit`メッセージ入力後にチェックしてくれるようになりました。**
お疲れ様です！


## （番外編）VScodeの自動保存で整形するようにする。

`ESLint`や`StyleLint`、`Prettier`をVScodeで上手に活用するための
VScodeの設定をここに記述します。
VScodeを利用している人は`setting.json`に以下を記述しておくといいでしょう。

```setting.json
{
  // デフォルトのフォーマッタを prettier に設定
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  // ファイル保存時、prettier による自動フォーマット
  "editor.formatOnSave": true,
  // ファイル保存時、ESLint による自動フォーマット
  "editor.codeActionsOnSave": {
    "source.fixAll": true
  },
  // css, scss ファイルは Stylelint でフォーマットするため、Pretteir によるフォーマットを回避
  "[css]": {
    "editor.formatOnSave": false
  },
  "[scss]": {
    "editor.formatOnSave": false
  },
  // VS Code の CSS, SCSS の Lint オフ
  // Stylelint とのバッティング回避
  "css.validate": false,
  "scss.validate": false
}
```

# `sass`の導入
パッケージをインストールするだけです。楽ちん。

```
npm install -D sass
```

# `dependabot`の導入

`dependabot`はプロジェクトで利用している依存ライブラリで
**新しいバージョンが出たら自動でPRを作ってくれる**という優れもの。

**長い間`npm audit`してなかったけど、気づいたら脆弱性がたっぷり**
ということにならないためにも、自動で管理してくれる`dependabot`を導入しておくのは
いい選択肢なのではないでしょうか。

また、作成されたPRを**条件付きの自動マージ**することもできるので、
その設定方法についても記して行きます。

**導入もシンプル**なので、早速やって行きましょう。

## `dependabot`の導入手順

`dependabot`に関しては**パッケージを入れる**ではなく、
**GitHubで設定する**という方法で導入することになります。

導入は至って**簡単**。何よりもこの[Gif動画](https://github.blog/wp-content/uploads/2021/04/how-to-view-dependency-graph-dependabot.gif)が一番分かりやすい。

一応画像でも示しておく。
1. GitHubへ飛んで、画面上部にある`inisights`のタブへ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/6d7af42b-1344-691f-2cf1-1293ccca6d90.png)

2. `Dependency graph`を選択し、`Dependabot`をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/d9fe5da0-8c01-e6a9-b796-8bf943c46b69.png)

3. `Enable Dependabot`をクリック→`Create config file`をクリック→適当にコミットメッセージを入れて`Commit new file`をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/0ae647fd-d827-9613-49ad-1feb4119aaea.png)

## (おまけ)`dependabot`で作成されたPRを自動マージしよう

`.github/workflows/`のディレクトリ配下に以下のファイルを作成することで、
GitHub Actions で自動で`dependabot`により作られたPRをマージしてくれます。

今回は**パッチバージョンの更新だけ自動マージするように設定しましょう。**

> パッチバージョンとは
ver. 1.12.**09** ← バージョン番号の右端。


```dependabot-auto-merge.yml
name: Dependabot auto-merge
on: pull_request # PRが上がったら実行するで

permissions:
  pull-requests: write
  contents: write

jobs:
  dependabot:
    runs-on: ubuntu-latest　 # ubuntuで実行するよ
    if: ${{ github.actor == 'dependabot[bot]' }} # PRあげたのがdependabotの時じゃないと実行しない
    steps:
      - name: Dependabot metadata
        id: metadata # このstepを`metadata`って名前で参照できるようにしとこ
        uses: dependabot/fetch-metadata@v1.1.1 # Dependabotが作成したPRから依存関係の情報を取得！
        with:
          github-token: '${{ secrets.GITHUB_TOKEN }}'
      - name: Enable auto-merge for Dependabot PRs
        if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' }} # パッチversionの更新じゃないなら処理しない。
        run: gh pr merge --auto --merge "$PR_URL" # mergeするよ
        env:
          PR_URL: ${{github.event.pull_request.html_url}}
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
```
参考
- [dependabot/fetch-metadata@v1.1.1とは](https://github.com/dependabot/fetch-metadata)
- [GitHub Actionsのワークフロー構文](https://docs.github.com/ja/actions/learn-github-actions/workflow-syntax-for-github-actions#jobs)

# MaterialUIの導入

**新しくアプリを作成する度、モーダルやボタンを一から自分で実装するのは**
**面倒なのですでに作成されているコンポーネントを使いまわせたらいいのになぁ**

そんな欲望の末に生み出されたモンスターが**MaterialUI**です。（違う）

基本的なコンポーネントの集まりで、必要に応じて自分でスタイルを変更できるので、
「あ、こいつ 既存のコンポーネント使いまわしてるのバレバレw」ともなりません。

似たようなものに[ChakuraUI](https://chakra-ui.com/)というものもあるみたいで、
こちらは**コンポーネント数は少ない**けどより**カスタム性に特化**したライブラリのようです。

こちらも興味あるのですが、今回は私が**使い慣れているMateriaUI**を入れていこうと思います。

## `MaterialUI`のインストール

以下のコマンドでインストールしましょう。

```
npm install @mui/material @emotion/react @emotion/styled @mui/icons-material
```

## `MaterialUI`のスタイルを上書きした時に、上書いたCSSを優先する

**自分で新たに追加したCSSよりもMaterialUIの持つスタイル情報が優先**されて、
**思ったように表示されない**なんてことがあります。
そのようなことを防ぐために、**上書きしたCSSを優先してね！という設定**を行う必要があります。

やり方は簡単です。
`pages`ディレクトリの下にある`_app.tsx`を以下のように書き換えましょう。

```_app.tsx
import '@/styles/globals.css';
import React from 'react';
import type { AppProps } from 'next/app';
import { StyledEngineProvider } from '@mui/material/styles'; // 追加

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <StyledEngineProvider injectFirst> // 追加
      <Component {...pageProps} />
    </StyledEngineProvider> // 追加
  );
}

export default MyApp;
```

`<Component {...pageProps} />`
を`<StyledEngineProvider>`というタグで囲っているだけですね。

これをするだけで、全てのコンポーネントで
**カスタムCSSを優先する**というルールが適用されることになります。

## (おまけ)`theme`の設定

`MaterialUI`にあるコンポーネントはデフォルトで
**色や文字サイズが適当な値**に設定されています。
例えば、デフォルトで`Button`コンポーネントはこんな色です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/8f4c4e7e-8d83-bf48-2e95-266cb667d7fe.png)

前述した通り、スタイルは自分で上書きできるのですが、
全てのコンポーネントで使用しているデフォルトの色を変更してあげれば、
わざわざ**上書き用のCSSを書く必要が無くなるので嬉しい**訳です。

そのような時に使えるのが`theme`という訳です。
**`theme`はデフォルトの値が詰まっている箱**みたいなもので、
この箱の値を変更してあげることで、**全てのコンポーネントでそれが適用されます。**

それでは実際にデフォルト値を変更してみます。
まずは好きな場所に**`theme.ts`というファイルを作りましょう**。
私は`styles`ディレクトリ直下に作ることにします。

```theme.ts
import { createTheme } from '@mui/material/styles';

// Create a theme instance.
const theme = createTheme({
  palette: {
    primary: { // ベースカラーを真っ黒にしちゃおう。
      main: '#000000'
    }
  }
});

export default theme;
```

次にこの定義した`theme`が**全てのコンポーネントで適用される**ようにしておきましょう。
`_app.tsx`に以下を追加して下さい。

```_app.tsx
import '@/styles/globals.css';
import { StyledEngineProvider, ThemeProvider } from '@mui/material/styles';  // ThemeProvider　を追加
import type { AppProps } from 'next/app';
import React from 'react';
import theme from '@/styles/theme'; // 追加

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <StyledEngineProvider injectFirst>
      <ThemeProvider theme={theme}> //追加
        <Component {...pageProps} />
      </ThemeProvider> //　追加
    </StyledEngineProvider>
  );
}
```

これだけです。
すると先ほどのボタンは真っ黒になっていると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/6741516d-88a5-b18b-bde5-c68d9c206bd1.png)

他にもテキストの大きさなども変えることができるので、必要ろあらばいじってみて下さい。

# `Jest`の導入

言わずと知れたテストライブラリです。
**私の個人開発だとテストは後回しになりがち**ですが、
**いつか書きたいとい気持ちも込めて入れておきます。**
結局やらないのであれば消すだけでOKなので...。

ここで紹介する導入ステップは以下の通りです。

1. **`Jest`のインストール**
1. **Jestの設定**
2. **仮テストの作成**

## `Jest`のインストール

以下のコマンドを実行しましょう

```
npm install -D jest @testing-library/react @types/jest @testing-library/jest-dom @testing-library/dom babel-jest @testing-library/user-event jest-css-modules
```

色々インストールしていますが、ざっくり言うと
「`Jest`で必要になるパッケージ諸々」＋「テストでCSSファイルが悪さしないようにモック化するパッケージ」
をインストールしています。

## Jestの設定

### `.babelrc`を作成する

`.babelrc`という名前でファイルを作成し、以下を記入して下さい。
これは、`Jest`に対して、「`Next.js`のプロジェクトにテストするよ」と伝えるために必要みたいです。

```.babelrc
{
  "presets": ["next/babel"]
}
```

### `package.json`に設定を追加する

`package.json`に以下の設定を追加しておきましょう。
コメントの部分は削除して下さい。

```package.json
    "jest": {
        "testPathIgnorePatterns": [　// テストの対象外となるディレクトリを記載
            "<rootDir>/.next/",
            "<rootDir>/node_modules/"
        ],
        "moduleNameMapper": {
            "\\.(scss)|(css)$": "<rootDir>/node_modules/jest-css-modules", // styleファイルに関しては`jest-css-modles`を使ってモックしますよ！
            "^@/(.*)$": "<rootDir>/src/$1" // import文が@で始まっていたら、それはsrcを示しているんだよ！
        }
    }
```

### `package.json`にテスト実行用のコマンドを追加

`package.json`の`script`に以下のコマンドを追加しておきましょう。

```package.json
    "scripts": {
        ...,
        "test": "jest --env=jsdom --verbose"
    }
```

**オプションは「テストファイルに対してテストが通ったかどうか？」**ではなく、
**「テストファイル内の全てのテストケースの結果を表示する」**ために必要なものになります。

## 仮テストの作成

**設定がうまくいっているかを確認する**ために、仮の簡単なテストを書いておきましょう。

まずは`___tests___`というディレクトリをルートに作成しましょう。
その中に仮のテストファイル`Home.test.tsx`というファイルを作成し、以下をコピペして下さい。


```Home.test.tsx
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import Home from '@/pages/index';

it('Should render hello text ', () => {
  render(<Home />);
  expect(screen.getByText('Next.js Template')).toBeInTheDocument();
});
```

`Jest`の話もしだすと長くなってしまうので、ざっくり説明すると、
**`<Home>`コンポーネントの中に`Next.js Template`という文字列が**
**あるかどうかを確認するよ！**というテストコードになります。

新しく作った`Next.js`のプロジェクトには`index.tsx`という名前のファイルが
あると思いますが、その中に`Home`コンポーネントが定義されているはずです。

その中に`Next.js Template`という文字列を含めておきましょう。
私は以下みたいな感じにしておきます。

```index.tsx
      ...
      <main className={styles.main}>
        <h1 className={styles.title}>
          Next.js Template /* ←ここに追加しました　*/
        </h1>

        <p className={styles.description}>
          Get started by editing <code className={styles.code}>pages/index.tsx</code>
        </p>
      ...
```

**これで`npm run test`を実行してみて下さい。**テスト通るはずです。
逆に`Next.js Template`の文字を削除してテストすると
エラーが表示されると思います。

**これでJestの導入は完了です！**
お疲れ様でした！

# StoryBookの導入

`StoryBook`。それは、デザイナーとの意思疎通を容易にするべく
作成したコンポーネントの**デザインを確認できるカタログを自動で生成**してくれる人。

**「個人開発で一人でやっているから、オイラは関係ないや。グヘヘェ」**
と私は思いました。

ですがこいつは**`見た目のテスト`をするためにも役立つ優れもの**だとか。
規模が大きくなり、１つのコンポーネントを複数の場所で使っていると
**いつの間にかスタイルおかしくなっている！**なんてことがあります。

それを防ぐことができるというのは嬉しいもの。
導入の手順は以下の通りです。

1. **`StoryBook`のインストール**
2. **`StoryBook`の設定変更**
3. **カタログを作ってみる**
4. **`Chromatic`のインストール**
5. **GitHub Actions の設定**

## `StoryBook` のインストール

とっても簡単です。以下のコマンドを実行するだけ！

```
npx sb init --builder webpack5
```

こちらを実行すると以下が行われます。

- パッケージのインストール
- コマンドのエイリアスを`package.json`に登録
- `.storybook`ディレクトリと設定ファイルの作成
- `stories`ディレクトリとサンプルファイルの作成

## `StoryBook`の設定変更

設定を少しだけいじります。
`.storybook`というディレクトリの中に`.main.js`というファイルがあるはずです。
こちらに**以下を追記してあげてください。**

```.main.js
const path = require('path'); // 追加

module.exports = {
  stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
  core: {
    builder: 'webpack5',
  },
  // ここから
  webpackFinal: async (config) => {
    config.resolve.alias = {
      ...config.resolve.alias,
      '@': path.resolve(__dirname, '../src'),
    };
    return config;
  }
  // ここまで追加
};
```

これは、`import`文が`@/...`というように`@`から始まっている場合でも
パスを認識できるようにするための設定です。

## カタログを作ってみる

カタログを作ってみましょう。
既存の`index.tsx`で定義されている`Home`コンポーネントをカタログに登録してみましょう。

まずは`stories`ディレクトリの中に`home.stories.tsx`というファイルを作成し、
以下をコピペしてあげてください。

```home.stories.tsx
import Home from '@/pages/index';

const home = {
  title: 'Pages/Home',
  component: Home,
};

export const HomePage = () => <Home />;

export default home;
```

続いてカタログをローカルサーバーで表示させるために以下のコマンドを実行します。

```
npm run storybook
```

そして[localhost:6006](http://localhost:6006)を見てみると、
画像のように`Home`コンポーネントがカタログに表示されいるのが確認できるでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/a6ef1f0f-9923-9fd6-875f-f291d9798c80.png)

:::note
デフォルトでは、サンプルのファイルが存在しているので、画像とは違ってHomeコンポーネント以外も表示されていると思います。この画像ではそれを消した状態のものです。
:::

ここまででひとまず`StoryBook`のカタログ機能に入門することができました。
**やったね☆**

## `Chromatic`のインストール

この説では**`Chromatic`と呼ばれるものをインストール**します。
これはStoryBookと連携して、**コンポーネントの見た目の変化を検知**し、
**比較検証を簡単にできる**ようにするツールです。

**まずは[Chromatic公式](https://www.chromatic.com/)へ飛んで`Get Started now`をクリック！**
そのまま案内に従ってポチポチしていくと以下のような画面に行くと思うので、
自分のリポジトリを選択してさらに進みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/99f0b297-eced-7270-098c-f64a92751225.png)

少し進むと**画面に表示されている２つのコマンドを実行してくれよな！**
と言われると思います。以下の２つのコマンドです。

```
npm install --save-dev chromatic
npx chromatic --project-token=プロジェクトごとの固有の値
```

素直に実行してみましょう。しばらく待つと画面遷移し、以下のような画面になると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/4996ecf5-3e7c-aeef-95a4-b9a325b5bf19.png)

すると今度は、「スタイルの違い検知してみせるから何かstyleいじってみろよ！」
と言われます。いじってやりましょう。なんでもいいのですが、
`Home.module.css`をいじってみることにします。

```Home.module.css
.main {
  align-items: center;
  display: flex;
  flex: 1;
  flex-direction: column;
  justify-content: center;
  min-height: 100vh;
  padding: 8rem 0; /* 変化させてみる 4rem -> 8rem */
}
```

そして再度、以下のコマンドを実行します。

```
npx chromatic --project-token=プロジェクトごとの固有の値
```

すると、`Chromatic`が変更を検知してみやすく表示してくれます。
以下のような感じです。素敵です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/082c98d6-47e8-cddb-7edc-3dfe1f189b34.png)

## GitHub Actions の設定

これまで`StoryBook`&`Chromatic`のカッコ良いところを見てきました。
でも**私の理想的なフローは以下なので、もう少し設定を頑張ります。**

1. GitHubでPR出した時に自動でチェック
2. 意図していない時に変更が検知されたら、それをチェックする。
3. 問題なければapproveしてmerge　！

そのためには**GitHub Actionsでワークフローを作成する必要があります。**
以下を`.github/workflows/`の直下に作成しましょう！

```chromatic-ui-test.yml
name: Chromatic

on:
  push: # pushされたら実行するよ
    branches:  # ブランチ名が以下じゃなければ実行しないよ
      - with_storybook # ここは適宜変更して下さい
jobs:
  build:
    runs-on: ubuntu-latest # ubuntu環境で実行します
  
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - run: npm ci
      - uses: chromaui/action@v1
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
```

このファイルで定義されている`CHROMATIC_PROJECT_TOKEN`という変数の値は、
GitHubに自分で定義する必要があります。
簡単にできるので、以下の手順で進めていきましょう！

まずはGitHubの`Setting`タブへ移動して下さい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/4946ebdc-85ee-0e9b-d6d5-b0e16e030140.png)

続いて、画面左側にある`Secrets`をクリック！
さらにさらに、`New repository secret`をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/4f680ab9-02f1-5f30-ec23-c48e55d71d3d.png)

`Name`に`CHROMATIC_PROJECT_TOKEN`と入力し、
`value`に自分のトークンを入力してください。
これで準備は完了です！

先ほど作った`chromatic-ui-test.yml`で定義したブランチ名でpushすれば、
`ChromaticUI`のチェックが実行されていることが確認できるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565905/87854fa4-d858-64ba-d3a2-68f50f775b1b.png)

お疲れ様です！これでUIテストを行う環境もできました！

# 最後に

**長かったですね。お疲れ様です。**

この記事の通りに実行して行っても`node`や`npm`,`yarn`の
バージョンの違いやOSの違いなどでエラーが出てしまって**「まぢムリ」**
となってしまうこともあるかもしれません。

**私はよくそういうことあります。**
エラーが出て、先人の奮闘記からコードをコピペしたけど
**やっぱり直らん。**ということが。

いつになったら英語の公式ドキュメントに臆さない
**キラキラスーパーエンジニアになれるのかは不明です。**

**今は個人開発などで色々奮闘しているので、**
**よかったら他の記事も見たりTwitterをフォローしてみましょう。**

[私のTwitter](https://twitter.com/wen_frt)

https://qiita.com/PonPon3/items/5ccfb487c6f49e438d63

https://qiita.com/PonPon3/items/8592588cd1a2601e1c35