こんにちは。ざわかける!のざわ(@zw_kakeru)です。
今回はJavaScriptに対してlintとformattingをgitのコミットフックで実行するように設定してみます。
バージョン確認
今回使うモジュール群のバージョンを確認しておきます。
- Node.js: 18.13.0
- npm: 8.19.3
- prettier: 2.8.3
- eslint: 8.33.0
- lint-staged: 13.1.0
- husky: 8.0.3
いずれも2023年1月現在リリースされている最新のバージョンです。
Nodeとnpmの導入
まず一番最初にNodeとnpmを入れます。
すでに入っている人が大半だと思いますので、そのような人はスキップしてください。
sudo apt install nodejs=18.13.0 #無理だったら18.xかも
基本的にこれで入ると思います。
私は変態なのでアーカイブを落としてくる↓の方法でやりました。
curl -sL https://deb.nodesource.com/setup_18.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo apt install nodejs
node -v #v18.13.0が出力される
npm -v #v8.19.3が出力される
rm nodesource_setup.sh
一応Nodeの公式サイトを見に行ってみましたが、最新版が正しくインストールされていることが分かりました。

各種モジュールの導入
Nodeが入ったので今回必要なモジュールを入れていきます。
npm install -D prettier@2.8.3 eslint@8.33.0 lint-staged@13.1.0 husky@8.0.3
バージョンを指定しなければ最新版が入りますが、特に複数人での共同開発を行う場合などは全員の環境で揃えておく必要があるのできちんとバージョンを指定することをオススメします。
prettierの設定
モジュールが揃ったのでここからは各種の設定をしていきます。
まずprettierからです。
prettierは前述のコマンドを叩くだけで手元で動くようになりますが、必要な人は.prettierrcや.prettierignoreを書きましょう。
私はタブ幅の設定が4にしたかった(デフォルトでは2)ので.pretteirrcを書きました。
{
"tabWidth": 4
}
eslintの設定
続いてeslintです。
eslintは先ほどのprettierと異なり、設定ファイル(.eslintrc)が必須となります。
自分で.eslintrcファイルを作成して配置してもいいのですが、コマンドで初期設定を行うことでも生成できます。
せっかくなのでコマンド生成してみます。
npm init @eslint/config
これを叩くとコマンドライン上でいろいろ聞かれるので、自分に合った設定をしていってください。

出力ファイル形式をyamlで指定してみたので、.eslintrc.ymlファイルが生成されました。
env:
browser: true
es2021: true
extends: eslint:recommended
overrides: []
parserOptions:
ecmaVersion: latest
lint-stagedの設定
linst-staged の設定です。
lint-stagedはeslintをかける際に、stagingにいるファイルのみを対象にするモジュールです。
すなわちgit commitを行うファイルに対してのみlintをかけてくれます。
変更が加わっていないファイルを毎回lintするのは意味がないですからね。
packege.jsonに次の内容を追加します。
{
...
"scripts": {
"lint-staged": "lint-staged",
"prettier": "prettier --write --no-error-on-unmatched-pattern './**/*.{js, ts}'",
"eslint": "eslint --no-error-on-unmatched-pattern './**/*.{js, ts}'"
},
"lint-staged": {
"*.js": [
"npx prettier",
"npx eslint"
],
"*.ts": [
"npx prettier",
"npx eslint"
]
...
}
scriptとしてlint-stagedを定義し、その中でjs、tsファイルに対してprettierとeslintをかけています。
prettierのフォーマットは自動上書きを許し、eslintは許さない構成にしてみました。
また、それぞれに–no-error-on-unmatched-patternのオプションが付いていますが、これは実行対象ファイルが存在しなかった場合にエラーを出力しないようにしています。
(エラーが無かったのかそもそも対象ファイル自体が無かったのかを区別するために、デフォルトでは対象ファイルが無かった時にはエラーとなるように設定されているのです。)
huskyの設定
最後に、このlint-stagedをコミットフックで呼び出すためのhusky設定を行います。
npx husky install
上記のコマンドを実行すると.huskyディレクトリが生成されるので中に入り、そこでpre-commitという名前のファイルを作成します。
その中に↓のように記述します。
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint-staged
package.jsonに記述されたlint-stagedスクリプトをコミットフックで呼び出しています。
そしてlint-stagedスクリプトではjsとtsに対してprettierとeslintをかける、という処理順になっています。
これで全ての作業が完了です。
完了
試しに次のようなtest.jsファイルを用意してみます。
function hello(name) {
document.body.textContent = "Hello, " + nama + "!"
}
hello("World");
このファイルをコミットしようとしたところ、

正しくエラー検出が行われました。
2行目にセミコロンが無いというエラーが出ていませんが、これはprettier側で先に整形した際につけてくれています。
おわりに
コミット時にlintが走ることで、勝手に綺麗なコードが書けるのはとても心地よいですね。
こういう自動化はどんどんやっていきたいものです。
一度でもやるともうそれが当たり前になるので、以降新規でリポジトリを作成した時などもサクサクっと設定してやりましょう。
ちなみに、huskyの優位点はpre-pushも設定することができることであり、今回のようにpre-commitしか設定しないのであればもしかしたら使わなくてよかったのかもしれませんね。
まあ私が賢くなったからヨシ!