Node.jsでgRPCを実装する前準備　.protoファイルの自動整形するための設定をやってみた

## はじめに
Node.jsでgRPC通信をやってみようと思い、.protoファイル（Protocol Buffers）を書き始めたがPrettierではコードフォーマットされず困った。

そこで今回は、.protoファイルでも自動整形が走るようにする設定をやってみた。自動整形の方法としてはエディター側で行う方法と、エディターによらずgit hooksを利用した方法の2つを設定してみた（エディターが異なる開発者がいても自動整形を行えるようにするには、git hooksなどを利用した設定が必要になるため）。

ソースコード全体は以下。

https://github.com/yuta-katayama-23/node-grpc/commit/7584ad3351a285647425daf182a322880733026c

## VS Codeの設定
今回はフォーマッターに[ClangFormat](https://clang.llvm.org/docs/ClangFormat.html)を利用する事にした。VS Codeの拡張機能としては[Clang-Format](https://marketplace.visualstudio.com/items?itemName=xaver.clang-format)になる。

設定方法としては、ClangFormat本体のコードやexeが必要になるので、それをインストールする。私はNodeなので以下のようにnode_modulesからClangFormatの本体を読み込むように設定した。その後、VS Codeのsettings.jsonを編集し、拡張機能をインストールすれば自動整形が走るようにできる。

```console
$ yarn add --dev clang-format
```
```json
// .vscode/settings.json
{
	"editor.formatOnSave": true,
	"clang-format.executable": "${workspaceRoot}/node_modules/.bin/clang-format",
	"clang-format.language.proto.style": "{ BasedOnStyle: Google }",
	"[proto3]": {
		"editor.defaultFormatter": "xaver.clang-format"
	}
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/bb7150bc-ef03-1456-8035-4499d3fde85e.png)

ClangFormatの本体をインストールしていたが、これは"clang-format.executable"の設定のためで、その事は公式の[Specifying the location of clang-format](https://marketplace.visualstudio.com/items?itemName=xaver.clang-format#specifying-the-location-of-clang-format)に記載がある。また、"clang-format.language.proto.style"の部分は、自分でフォーマットルールをカスタマイズするために設定する部分で、JSON形式で記載してフォーマットルールを設定できる。カスタマイズできるフォーマットルールのオプションは[Configurable Format Style Options](https://clang.llvm.org/docs/ClangFormatStyleOptions.html#configurable-format-style-options)に全量が書かれている。今回はGoogleのルールを採用する以外の設定は特にしていない。

・参考：[Visual Studio Code>Formatters>Clang-Format](https://marketplace.visualstudio.com/items?itemName=xaver.clang-format)  
・参考：[【VSC Tips】Clang-Formatの設定方法](https://opty-life.com/study/program/vsc-clang-format-setting/)  
・参考：[VSCodeでprotoファイルのフォーマットをする](https://zenn.dev/y16ra/articles/2a88926f71a744)

## git hooksの設定
エディタによらずコードフォーマットが効くようにするための設定も合わせて行う。この手はgit hooksでやる事が多いように思えるので、その設定をしていく。

やり方としては[Prettier のルールで自動整形する](https://note.com/shift_tech/n/n2a0b5561c27b#Prettier%20%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%A7%E8%87%AA%E5%8B%95%E6%95%B4%E5%BD%A2%E3%81%99%E3%82%8B)や[依存モジュール(ライブラリ)のライセンスをチェックする仕組みを導入してみた](https://note.com/shift_tech/n/n6fd1f955658b)で取り上げたやり方と全く同じで、git commit時（pre-commitフック）でコードのフォーマッティングが走るようにする。設定としては以下の通り。

```json
{
	...
	"scripts": {
		...
		"prepare": "npx simple-git-hooks"
	},
	"lint-staged": {
		"*": "npx prettier --ignore-unknown --write",
		"*.proto": "npx clang-format --style '{ BasedOnStyle: Google }' --files ./src/protos/* -i"
	},
	"simple-git-hooks": {
		"pre-commit": "npx lint-staged --verbose"
	}
}
```

上記にはprettierの設定も混じっているが、prettier側は[.prettierignore](https://prettier.io/docs/en/ignore.html)によりフォーマット対象からは除外している。clang-formatの設定は、npx clang-format -helpから確認できるコマンドオプションに基づき、VS Codeでのフォーマッティングと同じフォーマットになるようにしている。clang-formatで使えるオプションは以下の通り（一部に抜粋している）だが、--styleがフォーマットのルール設定をするためのオプションで、--filesがフォーマットする対象を設定するためのオプション。最後の-iはフォーマットした後にファイルの中身を上書きするか？どうかの設定で、指定するとフォーマットされた後の状態になる。

```console
[study@localhost node-grpc]$ npx clang-format -help
...
If <file>s are given, it reformats the files. If -i is specified
together with <file>s, the files are edited in-place. Otherwise, the
result is written to the standard output.

USAGE: clang-format [options] [<file> ...]

OPTIONS:

Clang-format options:

...
  --files=<string>               - Provide a list of files to run clang-format
  -i                             - Inplace edit <file>s, if specified.
...
  --style=<string>               - Coding style, currently supports:
                                     LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit.
                                   Use -style=file to load style configuration from
                                   .clang-format file located in one of the parent
                                   directories of the source file (or current
                                   directory for stdin).
                                   Use -style=file:<format_file_path> to explicitly specify
                                   the configuration file.
                                   Use -style="{key: value, ...}" to set specific
                                   parameters, e.g.:
                                     -style="{BasedOnStyle: llvm, IndentWidth: 8}"
...
```

※ちなみに、[clang-format](https://github.com/angular/clang-format)にはhuskyを使った例が書かれている。

## まとめとして
今回はProtocol Buffers（.protoファイル）を実装していく上で、自動整形が走るようにするための設定と、git hooksを利用して必ずコードフォーマットが走った後のコードがコミットされるようにする方法についてみてきた。この辺り、面倒なので後回しになりがちかもしれないが、チーム開発をする上ではレビューのしやすさ・保守性に関わる事なので、最初に設定していく事が後々の開発のしやすさにつながるのではないかと思う。

## おまけ
### VS Codeで.protoファイルを実装する時に便利なサジェスト拡張機能[vscode-proto3](https://marketplace.visualstudio.com/items?itemName=zxh404.vscode-proto3)
実装をする時にサジェストのない世界はつらい…という事で、.proto（Protocol Buffers）を実装する際に使える拡張機能を調べてみた所、[vscode-proto3](https://marketplace.visualstudio.com/items?itemName=zxh404.vscode-proto3)という拡張機能があり、これを利用する事で、1から自分で実装するのではなく、messageやserviceのひな形を修正する形で実装できるので便利だと思った。