[Flutter]コミット時に自動でformatする

# はじめに

Flutterにはコードをformatする機能が標準で用意されています。

しかし、コミット前にformatするのを忘れてしまい、
そのままpushしてしまうことは起こり得ますし、
コードがformatされていないかもしれないと思いながらレビューするのも面倒です。

そこで今回は lint-staged と husky を用いて

コミット時にコードを自動でformatできるようにします。

# lint-stagedとは

[lint-staged](https://www.npmjs.com/package/lint-staged)とは、ファイルがステージングしたファイルに対して任意の処理を実行できるツールです。

[npm](https://www.npmjs.com/package/lint-staged)で公開されています。

# huskeyとは

huskeyとは、コミットやプッシュなどのタイミングで任意の処理を実行できるツールです。

[npm](https://www.npmjs.com/package/husky)で公開されています。

Gitで特定のアクションが発生したときにカスタムスクリプトを実行する仕組みとして、Git hookがあります。

HuskeyはGit hookを用いており、[公式](https://typicode.github.io/husky/#/)によると依存関係ゼロ(’Zero dependencies’)であり、軽量であることなどが特徴です。

# 利用バージョン

- lint-staged: v12.4.1
- husky: v8.0.1
- yarn: v1.22.18

# 導入方法

## 注意

- anyenv経由でnodenvをインストール済みであることを前提としています

## 各種パッケージをインストール

導入に当たり必要なスクリプトを以下に示します。

```bash
# npmでyarnをローカルインストールする
sudo npm install yarn -d

# yarnでlint-staged, huskyをローカルインストールする
npx yarn add lint-staged husky -d

# huskyのセットアップを行う
npx husky-init

# アプリケーションにすべての依存をインストールするための処理を実行
npx yarn install
```

プロジェクトルートで上記スクリプトを実行すれば必要なツールがインストールされます。

## パッケージの初期設定

上記スクリプト内の `npx husky-init` を実行すると

- プロジェクトルートにpackage.jsonが追加されます
    - プロジェクト名やversion, authorなどの設定を聞かれるので答えていきます
        - 基本的にはenterを押していけばデフォルトの設定情報が登録されるので問題ないです
- .huskyフォルダ内にpre-commitファイルが追加されます

```
# package.json
{
  "name": "XXXXXX",
  "version": "1.0.0",
  "main": "index.js",
  "repository": "XXXXX",
  "author": "XXXXXX",
  "license": "MIT",
  "scripts": {
    "prepare": "husky install"
  },
  "dependencies": {
    "husky": "^8.0.1",
    "lint-staged": "^12.4.1",
    "yarn": "^1.22.18"
  }
}
```

```
# .husky/pre-commit

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

npm test
```

### pre-commit時に実行したいスクリプトを定義

package.jsonを編集します。

```
{
  "name": "hoge_mobile_01",
  "version": "1.0.0",
  "main": "index.js",
  "repository": "2022-05-11 15:16:52.927 xcodebuild[6620:52327] Requested but did not find extension point with identifier Xcode.IDEKit.ExtensionSentinelHostApplications for extension Xcode.DebuggerFoundation.AppExtensionHosts.watchOS of plug-in com.apple.dt.IDEWatchSupportCore\n2022-05-11 15:16:52.928 xcodebuild[6620:52327] Requested but did not find extension point with identifier Xcode.IDEKit.ExtensionPointIdentifierToBundleIdentifier for extension Xcode.DebuggerFoundation.AppExtensionToBundleIdentifierMap.watchOS of plug-in com.apple.dt.IDEWatchSupportCore\ngit@github.com:hoge/hoge_mobile.git",
  "author": "ykkd <ykkd221dev@gmail.com>",
  "license": "MIT",
  "scripts": {
    "prepare": "husky install"
  },
  "dependencies": {
    "husky": "^8.0.1",
    "lint-staged": "^12.4.1",
    "yarn": "^1.22.18"
  },

	# 以下を追加. dartファイルをコミットする前に `fvm flutter format`を実行する
  "lint-staged": {
    "*.dart": [
      "fvm flutter format"
    ]
  }
}
```

.huskey/pre-commitファイルを編集します

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

npx yarn lint-staged 
```

これで、dartファイルをコミットする際に、事前にformatする処理が追加できました。

### pathを通す

このままではhuskyの実行時に必要なツール(fvm, node)を見つけることができない場合があるため、

ルートディレクトリにある.huskyrcファイルを以下のように更新し、pathを通します。

```
# .huskyrc

export PATH="$PATH:$HOME/development/flutter/bin"

export PATH="$PATH:$HOME/.pub-cache/bin"

if [ -e "$HOME/.anyenv" ]
then
    export ANYENV_ROOT="$HOME/.anyenv"
    export PATH="$ANYENV_ROOT/bin:$PATH"
    if command -v anyenv 1>/dev/null 2>&1
    then
        eval "$(anyenv init -)"
    fi
fi
```

上から

- flutter
- fvm
- anyenv

のpathを通すための記述です.

今回はanyenv経由でnodenvを導入していますが、

nodebrewを利用していたり、anyenv経由で導入していない場合は、任意のpathに書き換えてください。

## 動作検証


試しにdartファイルにコメントを一行追加し、コミットしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605495/678c313d-d1c6-4c3b-7dad-3780e8c66fd3.png)


無事コミットのタイミングでコードの整形に成功しました🎉

# 導入後に別端末で利用可能にする

yarn initとpackage.jsonなどの設定はプロジェクトに対し一度設定すれば、他のチームメンバーがコミットする時もその設定を利用可能です。

しかし、必要なツールのインストールや、pathを通す処理は端末ごとに一度実行する必要があります。簡単にセットアップが完了するスクリプトを用意する手順を以下に示します。

- プロジェクトルートにscriptフォルダを新規作成し、フォルダ内に.huskyrc_tmpを配置します。
- 以下は.hukyrc_tmpの中身です

```bash

export PATH="$PATH:$HOME/development/flutter/bin"
export PATH="$PATH:$HOME/.pub-cache/bin"

if [ -e "$HOME/.anyenv" ]
then
    export ANYENV_ROOT="$HOME/.anyenv"
    export PATH="$ANYENV_ROOT/bin:$PATH"
    if command -v anyenv 1>/dev/null 2>&1
    then
        eval "$(anyenv init -)"
    fi
fi
```

- 次にMakefileにsetup用のステップを定義します

```bash
# Makefile

.PHONY: setup-precommit-tool
setup-precommit-tool: ## setup tools for linting at pre-commit
	sudo npm install yarn -d
	npx yarn add lint-staged husky -d
	npx yarn install
	# .huskyrc_cpの中身を.huskyrcに追記する
	cat script/.huskyrc_cp >> ~/.huskyrc
```

以上です。

これで、make setup-precommit-tool コマンドを一度実行することで、以降自動でformatするようになります。

# 参照

[lint-staged](https://www.npmjs.com/package/lint-staged)

[Husky - Git hooks](https://typicode.github.io/husky/#/)

[husky v6 のインストール方法と使い方。lint-staged も導入して、品質を保とう | fwywd（フュード）powered by キカガク](https://fwywd.com/tech/husky-setup)

[MVVM+Repositoryパターンを採用したFlutterアプリを構築する](https://zenn.dev/alesion/articles/ab2df82a3809b7#prettier%E3%81%AE%E5%B0%8E%E5%85%A5)

[JavaScript｜パッケージマネージャー「Yarn」の使い方 - わくわくBank](https://www.wakuwakubank.com/posts/307-javascript-yarn/)