Open12

個人開発におけるNext.jsの最小構成

takumitakumi

初期設定

プロジェクトのディレクトリ作成

mkdir next-app-template
cd next-app-template

nextアプリを作成

npm create next-app --typescript
npx: 1個のパッケージを2.137秒でインストールしました。
✔ What is your project named? … .
✔ Would you like to use ESLint with this project? … No / Yes
✔ Would you like to use Tailwind CSS with this project? … No / Yes
✔ Would you like to use `src/` directory with this project? … No / Yes
? Would you like to use experimental `app/` directory with this project✔ Would you like to use experimental `app/` directory with this project? … No / Yes
✔ What import alias would you like configured? … @/*

gitで管理

git init

適宜リポジトリを作成する
作成したら、リモートリポジトリを追加する

git remote add origin [リモートリポジトリurl]
git remote -v
origin	[リモートリポジトリurl] (fetch)
origin	[リモートリポジトリurl] (push)

pushする

git push -u origin main
takumitakumi

ESLintの設定

https://nextjs.org/docs/basic-features/eslint
https://eslint.org/docs/latest/use/configure/configuration-files
https://blog.ojisan.io/eslint-plugin-and-extend/

なるべくルールは厳しくつけたい。
主に以下のようなルールを設定したい。
※既に設定されているなどは関係なくとりあえず列挙する

  • import文の順番固定(internal, externalなど)
  • マジックナンバー禁止
  • シングルクオート
  • オブジェクトのキーとプロパティが一致しているときは省略する
  • 未使用の変数宣言を禁止
  • 未使用の式の使用を禁止
  • varの使用を禁止
  • useEffectなどの依存配列を適切にする
    など、今はそのくらい
takumitakumi

importの自動並べ替え

.eslintrc.jsonを以下のように編集

.eslintrc.json
{
  "extends": ["eslint:recommended", "next/core-web-vitals"],
  "plugins": ["import"],
  "rules": {
    "import/order": [
      "error",
      {
        "groups": ["builtin", "external", "internal"],
        "alphabetize": {
          "order": "asc"
        },
        "newlines-between": "always"
      }
    ]
  }
}

VSCodeのsettings.jsonを保存時にESLintのルールに沿って修正してくれるように編集

settings.json
{
  // エディタのフォーカスが外れた時に自動保存
  "files.autoSave": "onFocusChange",
  // 保存した際にESLintのルールに沿って修正
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

参考

https://qiita.com/yukiji/items/5ba9e065ac6ed57d05a4#vs-codeの設定

takumitakumi

ESLintのenv設定

https://zenn.dev/kimromi/articles/546923b7281dcb

.eslintrc.json
{
  "extends": ["eslint:recommended", "next/core-web-vitals"],
  "plugins": ["import"],
  "rules": {
    "import/order": [
      "error",
      {
        "groups": ["builtin", "external", "internal"],
        "alphabetize": {
          "order": "asc"
        },
        "newlines-between": "always"
      }
    ]
  },
+  "env" : {
+    "browser": true,
+    "node": true,
+    "es6": true
+  }
}

TypeScriptの設定

eslintrc.json
{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "next/core-web-vitals"
  ],
  "plugins": ["import", "@typescript-eslint"],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": "./tsconfig.json"
  },
  "rules": {
    "import/order": [
      "error",
      {
        "groups": ["builtin", "external", "internal"],
        "alphabetize": {
          "order": "asc"
        },
        "newlines-between": "always"
      }
    ]
  },
  "env" : {
    "browser": true,
    "node": true,
    "es6": true
  }
}
takumitakumi

Prettierの設定

インストール
eslint-config-prettiereslintprettierの重複ルールを無効化する

npm install -D prettier eslint-config-prettier

設定ファイル

.prettierrc.json
{
  "trailingComma": "all",
  "semi": true,
  "singleQuote": true
}
.eslintrc.json
{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "next/core-web-vitals",
+   "prettier"
  ],
  "plugins": ["import", "@typescript-eslint"],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": "./tsconfig.json"
  },
  "rules": {
    "import/order": [
      "error",
      {
        "groups": ["builtin", "external", "internal"],
        "alphabetize": {
          "order": "asc"
        },
        "newlines-between": "always"
      }
    ]
  },
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  }
}

takumitakumi

Reactの設定(ESLint)

npm install eslint-plugin-react eslint-plugin-react-hooks --save-dev
.eslintrc.json
{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
+   "plugin:react/recommended",
+   "plugin:react-hooks/recommended",
    "next/core-web-vitals",
    "prettier"
  ],
  "plugins": [
    "import",
    "@typescript-eslint"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": "./tsconfig.json"
  },
  "rules": {
    "import/order": [
      "error",
      {
        "groups": [
          "builtin",
          "external",
          "internal"
        ],
        "alphabetize": {
          "order": "asc"
        },
        "newlines-between": "always"
      }
    ]
  },
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  }
}

takumitakumi

ESLint設定ファイル

暫定的ではあるが設定ファイルはこうなった

.eslintrc.json
{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended",
    "plugin:react-hooks/recommended",
    "next/core-web-vitals",
    "prettier"
  ],
  "plugins": [
    "import",
    "@typescript-eslint"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": "./tsconfig.json"
  },
  "rules": {
    "no-else-return": "error",
    "object-shorthand": "error",
    "no-magic-numbers": "error",
    "camelcase": "error",
    "import/order": [
      "error",
      {
        "groups": [
          "builtin",
          "external",
          "internal"
        ],
        "alphabetize": {
          "order": "asc"
        },
        "newlines-between": "always"
      }
    ]
  },
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  }
}
takumitakumi

huskyとlint-stagedの設定

https://typicode.github.io/husky/#/

huskyインストール

npx husky-init && npm install 

.huskyディレクトリの中にpre-commitファイルが作成される。
この中にコミット前に実行したいコマンドを記述する。

ステージングに上がっているものだけESLintとPrettierを走らせたいためlint-stagedをインストール

npm install -D lint-staged

プロジェクトのルートに.lintstagedrc.jsonを作成し、ステージングされたファイルに対して実行したいコマンドを記述する。

.lintstagedrc.json
{
  "*.{js,jsx,ts,tsx}": ["eslint", "prettier --check"]
}

npm scriptに追加

package.json
 "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "prepare": "husky install",
+   "lint-staged": "npx lint-staged"
  },

.husky/pre-commitにコマンドを追加

npm run linst-staged

huskyとlint-stagedの設定完了

takumitakumi

コミットメッセージ自動チェック

commitlintの導入

https://commitlint.js.org/#/
https://commitizen.github.io/cz-cli/
https://zenn.dev/horitaka/articles/commit-message-rules

commitlint→コミットメッセージをチェック
commitizen→プロンプトからプレフィックスを選択

commitlintのインストール

npm install -D @commitlint/cli @commitlint/config-conventional

設定ファイル追加

echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js

動作確認

echo 'foo: bar' | commitlint
⧗   input: foo: bar
✖   type must be one of [build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test] [type-enum]

✖   found 1 problems, 0 warnings
ⓘ   Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint

huskyにcommit-msgフックを追加する

npx husky add .husky/commit-msg  'npx --no -- commitlint --edit ${1}'

commitizenの導入

インストール

npm install -D commitizen

リポジトリをcommitizenに対応させる

npx commitizen init cz-conventional-changelog --save-dev --save-exact

設定ファイル追加

.czrc
{
  "path": "cz-conventional-changelog"
}

npm scriptに追加

package.json
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "prepare": "husky install",
    "lint-staged": "npx lint-staged",
+   "commit": "cz"
  },

適当なファイルをaddして動作確認

npm run commit

> next-app-template@0.1.0 commit
> cz

cz-cli@4.3.0, cz-conventional-changelog@3.3.0

? Select the type of change that you're committing: (Use arrow keys)
❯ feat:     A new feature 
  fix:      A bug fix 
  docs:     Documentation only changes 
  style:    Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) 
  refactor: A code change that neither fixes a bug nor adds a feature 
  perf:     A code change that improves performance 
  test:     Adding missing tests or correcting existing tests 
(Move up and down to reveal more choices)

prepare-commit-msgフックでコミット時にプロンプト表示

npx husky add .husky/prepare-commit-msg  'exec < /dev/tty && node_modules/.bin/cz --hook || true'
takumitakumi

commitizenの追加設定

commitizenの日本語化

https://dev.classmethod.jp/articles/commitizen/

cz-conventional-changelog-jaのインストール

npm install -D cz-conventional-changelog-ja

設定ファイル変更

.czrc
{
  "path": "cz-conventional-changelog-ja"
}

commitizenの選択項目設定

https://qiita.com/manak1/items/e094338fd68e99d20876
https://github.com/leoforfree/cz-customizable

cz-customizableのインストール

npm install -D cz-customizable

設定ファイル追加

.cz-config.js
module.exports = {
  skipQuestions: ['scope', 'body', 'breaking', 'footer'],
};
takumitakumi

複数のadapterが使用できない問題

.czrcファイルに複数のadapterを設定したかったがどうやらまだ対応していない?
https://github.com/commitizen/cz-cli/issues/434

.cz-config.jsに以下を記述

.cz-config.js
module.exports = {
  types: [
    {
      value: '🌟 feat',
      name: 'feat: 機能追加',
      title: 'Features',
    },
    {
      value: '🔧 fix',
      name: 'fix: バグの修正',
      title: 'Bug Fixes',
    },
    {
      value: '🗒 docs',
      name: 'docs: ドキュメントのみの変更',
      title: 'Documentation',
    },
    {
      value: '🎨 style',
      name: 'style: コードの動作に影響しない、見た目だけの変更(スペース、フォーマット、欠落の修正、セミコロンなど)',
      title: 'Styles',
    },
    {
      value: '♻️ refactor',
      name: 'refactor: バグの修正や機能の追加ではないコードの変更',
      title: 'Code Refactoring',
    },
    {
      value: '⏫ perf',
      name: 'perf: パフォーマンスを向上させるコードの変更',
      title: 'Performance',
    },
    {
      value: '🧪 test',
      name: 'test: 不足しているテストの追加や既存のテストの修正',
      title: 'Tests',
    },
    {
      value: '🐧 chore',
      name: 'chore: ビルドプロセスやドキュメント生成などの補助ツールやライブラリの変更',
      title: 'Chores',
    },
  ],
  messages: {
    type: 'コミットする変更タイプを選択してください:\n',
    subject: 'コミット内容について入力してください:\n',
    confirmCommit: 'こちらの内容でコミットを実行してよろしいですか?:\n',
  },
  skipQuestions: ['scope', 'body', 'breaking', 'footer'],
};

.czrcを変更

.czrc
{
-  "path":  "cz-conventional-changelog-ja"
+ "path": "cz-customizable"
}

takumitakumi

最終的なcommitizenとcommitlintの設定

追加したライブラリ

  • @commitlint/cli
  • @commitlint/config-convectional
  • commitizen
  • cz-emoji

.czrc設定ファイル

.czrc
{
  "path": "cz-emoji",
  "config": {
    "cz-emoji": {
      "subjectMaxLength": 72,
      "skipQuestions": [
        "scope",
        "body",
        "breaking",
        "footer"
      ],
      "types": [
        {
          "emoji": "✨",
          "name": "feat",
          "code": "feat: :sparkles:",
          "description": "機能追加"
        },
        {
          "emoji": "🐛",
          "name": "fix",
          "code": "fix: :bug:",
          "description": "バグの修正"
        },
        {
          "emoji": "📚",
          "name": "docs",
          "code": "docs: :books:",
          "description": "ドキュメントのみの変更"
        },
        {
          "emoji": "🎨",
          "name": "style",
          "code": "style: :art:",
          "description": "コードの動作に影響しない、見た目だけの変更(スペース、フォーマット、欠落の修正、セミコロンなど)"
        },
        {
          "emoji": "♻️",
          "name": "refactor",
          "code": "refactor: :recycle:",
          "description": "バグの修正や機能の追加ではないコードの変更"
        },
        {
          "emoji": "🐎",
          "name": "perf:",
          "code": "perf: :horse:",
          "description": "パフォーマンスを向上させるコードの変更"
        },
        {
          "emoji": "✅",
          "name": "test: ",
          "code": "test: :white_check_mark:",
          "description": "不足しているテストの追加や既存のテストの修正"
        },
        {
          "emoji": "👷‍♂️",
          "name": "chore",
          "code": "chore: :construction_worker:",
          "description": "ビルドプロセスやドキュメント生成などの補助ツールやライブラリの変更"
        },
        {
          "emoji": "🗑",
          "name": "remove",
          "code": "remove: :wastebasket:",
          "description": "コードの削除"
        },
        {
          "emoji": "🚚",
          "name": "move",
          "code": "move: :truck:",
          "description": "リソースの移動や名前の変更"
        }
      ]
    }
  }
}
`skipQuestions`に設定できるもの

chatGPTに聞いてみた

commitlint設定ファイル

commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'feat',
        'docs',
        'style',
        'factor',
        'perf',
        'test',
        'chore',
        'remove',
        'move',
      ],
    ],
  },
};