lint-stagedでコミット対象ファイル以外をチェックする
チーフアクセシビリティエンジニア 黒澤lint-stagedはプレコミットフックなどで利用するツールで、通常はコミット対象ファイルをチェックします。ただ、要件によってはコミット対象ファイル以外をチェックしたほうが良い場合もあります。この記事ではlint-stagedでコミット対象ファイル以外をチェックする方法を紹介します。
通常の挙動とその限界
まずはlint-stagedの通常の挙動を確認します。*.jsに対してeslintを実行する設定をJSON形式で記述した例を考えてみます。
{
"**/*.js": "eslint"
}
この時、a.jsとb.jsをコミットしようとすると、単にeslintが実行されるのではなく
eslint /path/to/a.js /path/to/b.js
が実行されます。eslintはコマンドライン引数で与えられたファイルをチェックするため、a.jsとb.jsのみをチェックします。eslintはコミット対象ファイルのみをチェックするので、全ファイルをチェックするよりも早く処理を終えられます。
一方、チェック対象のファイルパスをコマンドに渡すと上手くいかない場合もあります。
例えば、開発者が触れるファイルとユーザーが触れるファイルが異なる場合に、ユーザーが触れるファイルの品質をチェックしたいケースです。
より具体的な例を挙げると、*.ejsから*.htmlを生成している場合に*.htmlをチェックするにはどうしたら良いでしょうか。
※以降の説明ではHTMLのチェックツールとして@mitsue/vlint(vlintコマンド)を用いますが、必要に応じて他のチェックツールに読み替えてください。
*.ejsから*.htmlを生成している場合、コミットするのは通常*.ejsのみなので、*.ejsに対してvlintを実行させると次のような記述になります(JSON形式での設定例)。
{
"**/*.ejs": "vlint"
}
この時a.ejsとb.ejsをコミットしようとすると
vlint /path/to/a.ejs /path/to/b.ejs
が実行されます。vlintもコマンドライン引数で与えられたファイルをチェックするため、a.ejsとb.ejsのみをチェックします。しかし、vlintはejsをチェックできないため、*.ejsが渡されるとエラー終了します(プレコミットフックが失敗し、コミットに失敗します)。
対応方法
この問題の対応方法は少なくとも2つあります。
- コマンドに渡すファイルパスを変換する
- コマンドにファイルパスを渡さない
コマンドに渡すファイルパスを変換する
コマンドに渡すファイルパスを変換する方法では、例えば、*.ejsのファイルパスを*.htmlのファイルパスに変換してからvlintコマンドに渡します。
具体的にはa.ejsとb.ejsをコミットしようとした時に
vlint /path/to/a.html /path/to/b.html
を実行するように設定します。lint-stagedの設定をJavaScriptで記述するとファイルパスの変換処理を実装できます。
// lint-staged.config.mjs
export default {
// filenamesは['/path/to/a.ejs', '/path/to/b.ejs']形式
'**/*.ejs': (filenames) => {
// ファイルパスを変換するコードを記述
const htmlPaths = filenames.map((filename) => filename.replace('.ejs', '.html'));
return [
// 変換したファイルパスをコマンドに渡す
`vlint ${htmlPaths.map((htmlPath) => `"${htmlPath}"`).join(' ')}`,
];
},
};
コマンドにファイルパスを渡さない
コマンドにファイルパスを渡さない方法では、例えば、コミット対象ファイルに関係なく
vlint
を実行します。vlintコマンドはファイルパスを指定せずに実行すると対象の全HTMLファイルをチェックします。
vlintはキャッシュ機能を有効にすると前回チェック時から変更されたファイルのみチェックしますので、実質的に、コミット対象*.ejsファイルに対応する*.htmlファイルのみをチェックできます。キャッシュ機能を有効にするには--cacheを指定します。
vlint --cache
ここまでの内容をlint-stagedに設定すると次のようになります。
// lint-staged.config.mjs
export default {
// filenamesは['/path/to/a.ejs', '/path/to/b.ejs']形式
'**/*.ejs': (filenames) => [
// filenamesに関係なくvlint --cacheを実行
'vlint --cache',
],
};
おわりに
この記事はlint-stagedでコミット対象ファイル以外をチェックする方法を紹介しました。開発者が触れるファイルとユーザーが触れるファイルが異なる場合に、ユーザーが触れるファイルの品質をチェックしたいケースで参考になれば幸いです。
なお、lint-stagedのREADME.mdではさらなるユースケースが紹介されていますので、興味のあるかたはご一読ください。