Motomichi Works Blog

モトミチワークスブログです。その日学習したことについて書いている日記みたいなものです。

lint-stagedとhuskyを使ってgit commitする前にeslint、stylelint、prettierを実行する

参考にさせていただいたページ

はじめに

lint-stagedとhuskyをインストールして、Next.jsアプリケーションの開発環境に設定します。

今回の環境

  • macOS Monterey 12.6.2
  • node 19.4.0
  • npm 9.2.0
  • husky 8.0.3
  • lint-staged 13.1.2
  • next 13.1.2

lint-staged huskyをインストールする

以下のコマンドを実行します。

npm install --save-dev lint-staged husky

huskyをセットアップする

Husky - Git hooks」に倣って、以下の通り実行しました。

npx husky-init && npm install

このとき、package.jsonとpackage-lock.jsonが更新されます。

また以下の .husky/pre-commit ファイルが、以下の記述内容で作成されます。

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm test

.husky/pre-commitを編集する

pre-commit時に実行するコマンドを変更します。

husky-initコマンドによって生成された.husky/pre-commitファイルは、npm testコマンドを実行する設定になっているので、これを変更します。

以下の通り、lint-stagedを実行するようにして、上書き保存します。

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged

lint-stagedの設定ファイルを作成して設定する

.lintstagedrc.jsファイルの作成

以下のコマンドを実行します。

vim .lintstagedrc.js

next lintだけ実行する場合の記述内容

今回はNext.jsのアプリケーションなので、Next.jsの公式ページ「Basic Features: ESLint | Next.js」に倣って以下の記述内容で作成しました。

const path = require('path')

const buildEslintCommand = (filenames) =>
  `next lint --fix --file ${filenames
    .map((f) => path.relative(process.cwd(), f))
    .join(' --file ')}`

module.exports = {
  '*.{js,jsx,ts,tsx}': [buildEslintCommand],
}

stylelintとprettierも実行したい場合の記述内容

上記の設定だけだとnext lintしか実行されないので、stylelintとprettierも実行したい場合は以下のようにします。

const path = require('path');

const buildEslintCommand = (fileNames) => {
  const fileNamesStr = `--file ${fileNames
    .map((f) => path.relative(process.cwd(), f))
    .join(' --file ')}`;
  return `next lint --fix ${fileNamesStr}`;
};

const buildStylelintCommand = (fileNames) => {
  const fileNamesStr = fileNames
    .map((f) => `'${path.relative(process.cwd(), f)}'`)
    .join(' ');
  return `stylelint --fix ${fileNamesStr}`;
};

const buildPrettierCommand = (fileNames) => {
  const fileNamesStr = fileNames
    .map((f) => `'${path.relative(process.cwd(), f)}'`)
    .join(' ');
  return `prettier --write ${fileNamesStr}`;
};

module.exports = {
  '*.{js,jsx,ts,tsx}': [
    buildEslintCommand,
    buildStylelintCommand,
    buildPrettierCommand,
  ],
};