ある特定のファイルが更新されたらコマンドを実行する
フロントエンドやバックエンドを Node.js でチーム開発をしていると package.json
が更新されているのに、気づかずそのまま実行してエラーが出るみたいな現象が生じがちです。
コミュニケーションその他でカバーすることも可能ですが、我々プログラマたるもの、全て自動でやるべきです。そこで、Git の pre commit hook に使われることの多い husky を使って、更新を検知してフック処理を実行してみましょう。
husky
Husky は package.json 上で、Git フックをいい感じに扱える便利なパッケージです。よく使われるパターンは lint-staged
というパッケージと組み合わせて、コミット時に eslint や prettier あるいは TypeScript の型チェックを走らせるという用途が多いでしょう。それらの資料は山程転がってるので、そちらに興味がある人はいい感じにぐぐってください。
他者による package.json の更新を検知する
さて今回の目的は、誰かが package.json
を更新したら npm i
もしくは yarn
を実行して、パッケージを更新したいというものです。
自分が package.json
を更新した場合は、自分自身でパッケージをインストールしてるはずなので、誰か他の人のコミットを取り込んだときに、package.json
の更新を検知できれば良いでしょう。
Husky が対応しているフックには post-merge
とか post-checkout
というものがあります。
"husky": {
"hooks": {
"post-merge": "node scripts/install.js",
"post-checkout": "node scripts/install.js"
}
}
Git で merge, rebase や checkout をしたら scripts/install.js
を走らせるようにしましょう。
scripts/install.js
/* eslint-disable */
const { execSync } = require('child_process')
try {
const stdout = execSync("git diff 'HEAD@{1}' --name-only").toString('utf-8')
const changedFiles = stdout
.trim()
.split('\n')
.filter((name) => ['package.json'].includes(name))
// 他のファイル、たとえば `api.yaml` もチェックしたいなら配列に追加する
if (changedFiles.length > 0) {
execSync('npm i', { stdio: 'inherit' })
}
} catch (e) {
console.warn(e)
console.log('you need npm install.')
}
process.exit(0)
git diff 'HEAD@{1}' --name-only
で変更のあったファイル一覧を取得できるので、この中に package.json
が含まれてないかを確認しています。変更があれば npm i
を実行しています。
OpenAPI の更新を検知して、自動生成する
OpenAPI Generator typescript-fetch を使う に書いたような API 生成を行っている場合は、OpenAPI の定義ファイルが更新されたら、自動生成を走らせたいですよね???
先程の scripts/install.js
の .filter((name) => ["package.json"].includes(name));
に、対象ファイル名を追加しておきましょう。
その場合、OpenAPI の定義ファイルを更新したのに、なぜ npm i
でパッケージ更新するのか?という疑問が出るのは当然です。
ここで少しトリックをいれます。
package.json
の scripts
に postinstall
という項目を追加します。
"scripts": {
"dev": "next dev",
"postinstall": "npm run generate:api-client",
"generate:api-client": "openapi-generator-cli generate -g typescript-fetch -i <OpenAPI定義ファイル> -o <生成ディレクトリ> --additional-properties=modelPropertyNaming=camelCase,supportsES6=true,withInterfaces=true,typescriptThreePlus=true"
}
たとえばこのように、postinstall
で npm run generate:api-client
を実行するようにしておくのです。
まとめ
- Husky で、git checkout や merge/rebase などでスクリプトを走らせられる
- スクリプトで、特定ファイルの更新を検知して
npm i
を走らせる - API クライアントの自動生成を
package.json
のpostinstall
で実行する
これによって、手動で更新するという非人道的なことをしなくて済む、素敵なプロダクトになりました。素晴らしいですね。
Discussion